При подготовке нашей службы данных WCF к производству мы столкнулись с проблемой с поведением оператора расширения при включенном разбиении по страницам.
Если разбиение по страницам отключено, расширение работает должным образом. Но когда я включаю разбиение на страницы для любого из расширенных наборов объектов, независимо от размеров страницы, развернутые объекты отображаются на странице с размером 1.
[ОБНОВЛЕНИЕ]
В отсутствие каких-либо дополнительных сведений отсюда или форумов MSDN я создал ошибка при подключении. Может, кто-нибудь через стену докопается до сути!
Например, предположим, что у меня есть следующая простая модель:
Он работает в сгенерированной базе данных SQL с некоторыми примерами данных:
INSERT INTO [dbo].[Towns] (Name) VALUES ('Berlin');
INSERT INTO [dbo].[Towns] (Name) VALUES ('Rome');
INSERT INTO [dbo].[Towns] (Name) VALUES ('Paris');
INSERT INTO [dbo].[Gentlemen] (Id, Name) VALUES (1, 'Johnny');
INSERT INTO [dbo].[Ladies] (Name, Town_Name, Gentleman_Id) VALUES ('Frieda', 'Berlin', 1);
INSERT INTO [dbo].[Ladies] (Name, Town_Name, Gentleman_Id) VALUES ('Adelita', 'Berlin', 1);
INSERT INTO [dbo].[Ladies] (Name, Town_Name, Gentleman_Id) VALUES ('Milla', 'Berlin', 1);
INSERT INTO [dbo].[Ladies] (Name, Town_Name, Gentleman_Id) VALUES ('Georgine', 'Paris', 1);
INSERT INTO [dbo].[Ladies] (Name, Town_Name, Gentleman_Id) VALUES ('Nannette', 'Paris', 1);
INSERT INTO [dbo].[Ladies] (Name, Town_Name, Gentleman_Id) VALUES ('Verona', 'Rome', 1);
INSERT INTO [dbo].[Ladies] (Name, Town_Name, Gentleman_Id) VALUES ('Gavriella', 'Rome', 1);
Служба данных проста (обратите внимание, что здесь отключена подкачка):
namespace TestWCFDataService
{
public class TestWCFDataService : DataService<TestModel.TestModelContainer>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Ladies", EntitySetRights.AllRead);
config.SetEntitySetAccessRule("Gentlemen", EntitySetRights.AllRead);
config.SetEntitySetAccessRule("Towns", EntitySetRights.AllRead);
//config.SetEntitySetPageSize("Ladies", 10);
//config.SetEntitySetPageSize("Gentlemen", 10);
//config.SetEntitySetPageSize("Towns", 10);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
}
Теперь мой пользователь хочет найти всех Lady
, Town
которых - "Берлин", а также их Gentleman
.
Рассматриваемый запрос:
http://localhost:62946/TestWCFDataService.svc/Towns('Berlin')?$expand=Ladies/Gentleman
Когда я запускаю этот запрос (JSON, потому что версия Atom гигантская), я получаю ожидаемый результат; город с тремя дамами, джентльменами каждой из которых является Джонни.
var result = {
"d": {
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Towns('Berlin')", "type": "TestModel.Town"
}, "Name": "Berlin", "Ladies": [
{
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Ladies(1)", "type": "TestModel.Lady"
}, "Id": 1, "Name": "Frieda", "Gentleman": {
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Gentlemen(1)", "type": "TestModel.Gentleman"
}, "Id": 1, "Name": "Johnny", "Ladies": {
"__deferred": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Gentlemen(1)/Ladies"
}
}
}, "Town": {
"__deferred": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Ladies(1)/Town"
}
}
}, {
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Ladies(2)", "type": "TestModel.Lady"
}, "Id": 2, "Name": "Adelita", "Gentleman": {
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Gentlemen(1)", "type": "TestModel.Gentleman"
}, "Id": 1, "Name": "Johnny", "Ladies": {
"__deferred": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Gentlemen(1)/Ladies"
}
}
}, "Town": {
"__deferred": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Ladies(2)/Town"
}
}
}, {
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Ladies(3)", "type": "TestModel.Lady"
}, "Id": 3, "Name": "Milla", "Gentleman": {
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Gentlemen(1)", "type": "TestModel.Gentleman"
}, "Id": 1, "Name": "Johnny", "Ladies": {
"__deferred": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Gentlemen(1)/Ladies"
}
}
}, "Town": {
"__deferred": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Ladies(3)/Town"
}
}
}
]
}
}
В конечном итоге их будет много Towns
, поэтому я включаю пейджинг для города.
...
config.SetEntitySetPageSize("Towns", 10);
...
Запрос продолжает функционировать, как ожидалось. Но также будет много Ladies
и Gentlemen
, поэтому я хочу иметь возможность ограничить количество возвращаемых результатов:
...
config.SetEntitySetPageSize("Ladies", 10);
config.SetEntitySetPageSize("Gentlemen", 10);
...
Но когда я устанавливаю размер страницы либо для набора сущностей Ladies, либо для набора сущностей Gentlemen (или обоих), результаты моего запроса неожиданно меняются:
var result = {
"d": {
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Towns('Berlin')", "type": "TestModel.Town"
}, "Name": "Berlin", "Ladies": {
"results": [
{
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Ladies(1)", "type": "TestModel.Lady"
}, "Id": 1, "Name": "Frieda", "Gentleman": {
"__metadata": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Gentlemen(1)", "type": "TestModel.Gentleman"
}, "Id": 1, "Name": "Johnny", "Ladies": {
"__deferred": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Gentlemen(1)/Ladies"
}
}
}, "Town": {
"__deferred": {
"uri": "http://localhost:62946/TestWCFDataService.svc/Ladies(1)/Town"
}
}
}
]
}
}
}
Расширение включает только один из объектов Леди (хотя включен, по крайней мере, ее Джентльмен). Неважно, насколько велик установлен размер страницы, запрос по-прежнему возвращает только один объект в расширенной коллекции.
Также не имеет значения, установлен ли размер страницы для одного или обоих развернутых объектов, если для одного из них задан размер страницы, то только один из Lady
объектов будет загружен без промедления.
Такое поведение кажется мне ошибочным, поскольку согласно спецификации OData:
«URI с параметром системного запроса $ expand указывает, что записи, связанные с записью или коллекцией записей, идентифицированной разделом« Путь к ресурсам »URI, должны быть представлены встроенными (т. Е. Быстро загруженными)».
Я неправильно читаю спецификацию? Должен ли я ожидать такого поведения? Я просто хочу иметь возможность ограничивать размер страницы наборов сущностей при прямом доступе, но также иметь возможность загружать их.
Это ошибка в службах данных WCF? (или мой код? или мой мозг?)
[РЕДАКТИРОВАТЬ]
Дополнительная информация: в документации для служб данных WCF говорится, что:
«Кроме того, когда в службе данных включена подкачка, вы должны явно загружать последующие страницы данных из службы».
Но я не могу найти объяснения, почему размер страницы для связанных наборов сущностей, по-видимому, по умолчанию равен 1, независимо от того, какой размер страницы указан.
[РЕДАКТИРОВАТЬ]
Еще больше информации: рассматриваемая версия находится на .NET 4 версии 4.0.30319
с System.Data.Services
версией 4.0.0.0
. Это версия, которая идет в комплекте с Visual Studio 2010 (с установленным SP1).
[РЕДАКТИРОВАТЬ]
Пример решения, демонстрирующего поведение, теперь находится в репозитории github. В нем включена разбивка на страницы в методе InitializeService
и в сценарии создания БД, который также добавляет некоторые образцы данных, так что мы находимся на одной странице.