При подготовке нашей службы данных WCF к работе мы столкнулись с проблемой поведения оператора расширения при включенном разбиении на страницы.
Если страница отключена, расширение работает, как ожидается. Но когда я включаю разбиение на страницы на любом из расширенных наборов сущностей, независимо от размера страницы, развернутые сущности отображаются на странице размером 1.
[UPDATE]
В отсутствие каких-либо дополнительных комментариев здесь или на форумах MSDN я создал ошибку в Connect . Может быть, кто-то за стеной докопается до сути!
Например, предположим, у меня есть следующая простая модель:
Он работает в сгенерированной базе данных 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
, поэтому я включаю пейджинг для Town.
...
config.SetEntitySetPageSize("Towns", 10);
...
Запрос продолжает работать, как ожидалось. Но также будет много Ladies
и Gentlemen
, поэтому я хочу иметь возможность ограничить количество возвращаемых результатов:
...
config.SetEntitySetPageSize("Ladies", 10);
config.SetEntitySetPageSize("Gentlemen", 10);
...
Но когда я устанавливаю размер страницы в наборе сущностей Леди или в наборе сущностей Джентльменов (или обоих), результаты моего запроса неожиданно меняются:
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? (или мой код? или мой мозг?)
[EDIT]
Дополнительная информация: в документации для Служб данных WCF указано, что:
"Кроме того, когда в службе данных включена подкачка страниц, необходимо явно загрузить последующие страницы данных из службы."
Но я не могу найти объяснение того, почему размер страницы для связанных наборов сущностей по умолчанию равен 1, независимо от того, какой размер страницы указан.
[EDIT]
Еще больше информации: рассматриваемая версия - версия .NET 4 4.0.30319
с System.Data.Services
версия 4.0.0.0
. Это версия, поставляемая в комплекте с Visual Studio 2010 (с установленным пакетом обновления 1).
[EDIT]
Пример решения, показывающего поведение, теперь работает в github репозитории . Он включает подкачку в методе InitializeService
и сценарии создания БД, который также добавляет некоторые примеры данных, чтобы мы были на одной странице.