设置某些实体页面大小时,WCF数据服务展开意外行为

时间:2011-05-10 02:00:38

标签: c# entity-framework odata wcf-data-services

在准备好生产WCF数据服务的同时,我们在启用分页时遇到了扩展运营商行为的问题。

禁用分页后,展开按预期工作。但是当我在任何扩展实体集上启用分页时,无论页面大小如何,扩展实体的页面大小都会为1。

[UPDATE]

如果没有来自此处或MSDN论坛的任何进一步输入,我创建了bug on Connect。也许墙上的人会触及它的底部!

例如,假设我有以下简单模型: Example Model

它在生成的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);
...

查询继续按预期运行。但是也会有很多LadiesGentlemen所以我希望能够限制返回的结果数量:

...
            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对象(尽管至少包括她的绅士)。无论页面大小设置为多大,查询仍然只返回展开集合中的一个对象。

无论是否在一个或两个扩展实体上设置页面大小也无关紧要,只要其中一个设置了页面大小,那么Lady个对象中只有一个会热切地加载。

根据OData Specification

,这种行为给我带来了麻烦
  

“具有$ expand系统查询选项的URI表示与URI的资源路径部分标识的条目或条目集合关联的条目必须以内联方式表示(即急切加载)。”

我误读了这个规格吗?我应该预料到这种行为吗?我只是希望能够在直接访问时限制实体集的页面大小,但也可以加载它们。

这是WCF数据服务中的错误吗? (或我的代码?还是我的大脑?)

[编辑]

更多信息:documentation for WCF Data Services表示:

  

“此外,在数据服务中启用分页时,您必须从服务中显式加载后续数据页。”

但是我无法找到解释为什么无论指定的页面大小如何,相关实体集的页面大小似乎默认为1。

[编辑]

更多信息:有问题的版本是使用4.0.30319版本System.Data.Services的.NET 4版本4.0.0.0。它是Visual Studio 2010(已安装SP1)的包装盒中的版本。

[编辑]

显示行为的示例解决方案现在位于github repository。它在InitializeService方法和数据库创建脚本中打开了分页,该脚本还添加了一些示例数据,以便我们在同一页面上。

3 个答案:

答案 0 :(得分:1)

花了几个月但是apparently将在下一个版本中修复:

  

Microsoft于12/15/2011上午8:08发布

     

感谢您报告此问题。我们已确认实体框架中存在错误   造成这个问题。修复程序需要更改发布的核心Entity Framework组件   在.NET Framework中。我们修复了这个bug,修复程序将包含在下一个版本中   .NET Framework。

答案 1 :(得分:0)

您使用的是哪种版本的WCF数据服务? 我发现有一个错误与在.NET Framework 4中使用Expand与服务器驱动的分页有关,但我认为它只影响具有复合键的实体,并且在使用OrderBy选项时,这两个似乎都不适用于此处。 它仍然听起来像一个错误。

您是否尝试过使用Atom而不是JSON,如果是,那么扩展中的实体仍然缺失?

答案 2 :(得分:0)

您的查询: localhost:62946 / TestWCFDataService.svc / Towns('Berlin')?$ expand = Ladies / Gentleman

不会扩展Ladies,只会扩展Gentelman。

查询应如下所示:

本地主机:?62946 / TestWCFDataService.svc /村庄( '柏林')$扩大=女士,女士/绅士

希望这有帮助!

Monica Frintu