2011-10-04 62 views
3

如果我在web项目中使用我的实体模型,我可以导航到1- * 1-0.1 nav属性,但是当我加载确切的通过LinqPad在我的oData服务相同的对象导航属性始终为空为什么我的oData服务(实体框架)不允许导航属性

...我做错了什么?...应该启用某种方式吗?

如果我加载了小提琴手和运行查询http://odata.site.com/Service1.svc/usda_FOOD_DES(1001)/usda_ABBREV

...它返回正确的结果

谢谢你,史蒂夫

+0

你是什么意思“加载LinqPad”,你可以请你张贴在LinqPad中运行的查询吗? –

回答

4

我问自己同样的问题。我想知道为什么下面的返回一个空集:

Customers.Where(c => c.ID == 1).Single().Orders 

的原因是,不像实体框架的导航性能,当你访问一个OData的实体的属性不会自动返回到数据源和检索任何尚未存在的数据。因此,当您从OData Feed中检索实体时,默认情况下它不包含链接的实体,因此您可以为一对多或多对多导航属性获取空的IEnumerable<T>,或者对于单个实体导航属性为空。

你会期待上面的查询翻译成:

HTTP; // odata.sample.com/MyODataFeed.svc/Customers(1)/Orders

这将返回所有订单,而是将它转换为这个(看到LINQPad查询,请单击结果窗格上方的SQL按钮):

HTTP; // odata.sample.com/MyODataFeed.svc/Customers(1)

这是因为.Orders最后不在任何扩展方法内,所以不参与IQueryable的构造。因此,它不反映在从查询构建的URL中,也不包含在结果集中。

那么如何才能得到客户1的订单?您可以尝试通过使用下面的查询解决此问题:

Customers.Where(c => c.ID == 1).Select(a => c.Orders) 

这应该引起包括在查询中.Orders财产。不幸的是,.Select(...)没有将结果投影到匿名方法(即new { ... })是不允许的,并抛出NotSupportedException: The method 'Select' is not supported.真是太遗憾了。那么,关于:

Customers.Where(c => c.ID == 1).Select(a => new { c.Orders }) 

不会产生预期的结果,而是执行以下查询:

HTTP; // odata.sample.com/MyODataFeed.svc/Customers(1) ?$ expand = Orders & $ select = Orders

我不明白为什么这不会被翻译成/ Customers(1)/ Orders。在任何情况下,它都会将订单列表放在一个不需要的包装类中,这可能非常烦人,但它起作用,并且它是我能够仅检索导航属性内容的最接近的工具。

我更喜欢的方法,是在包括所有与每个客户的订单,像这样:

Customers.Expand("Orders").Where(c => c.ID == 1).Single().Orders 

这将产生以下查询:

HTTP; // odata.sample.com/ MyODataFeed.svc/Customers(1)?$ expand =订单

这样做有效,但有缺点,即包括我们可能不需要的所有客户详细信息。另外,.Expand(...)的字符串有问题 - 它的输入很弱,所以它不会被编译器验证(注意拼写错误),并非所有的重构工具都会重构它,查找该属性的所有用法都不会在搜索结果中包含该字符串等。

+0

'Customers.Single(c => c.ID == 1).Select(a => new {c.Orders})''怎么办?我没有OData项目设置来测试它,但我认为这将返回一个IEnumerable,而不是嵌套在一个包装器中的IEnumerable。 –

+1

@JoelC:你不能在OData中使用'.Single(...)'的重载,只能使用无参数重载'.Single()'(并且只有当感觉就像让你)时。即使你可以,'.Single(...)'返回一个'Customer'类,它不是'IEnumerable ',所以你不能使用任何LINQ操作符(比如'.Select(...) )')。即使你可以使用'.Select(...)',你的代码仍然会创建一个名为'Orders'的单个属性的匿名类,它将被赋值为'c.Orders', d仍然有包装类。 –

0

最新版本v4 Asp.Net o http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/working-with-entity-relations oData支持 使用导航属性有一个更好的解决方案。

支持的网址:

GET /Products(1)/Supplier 

报价: 这里的“供应商”是对产品类型的导航性能。在这种情况下,供应商引用单个项目,但导航属性也可以返回集合(一对多或多对多关系)。

为了支持此请求中,添加以下方法将ProductsController类:

// GET /Products(1)/Supplier 
public Supplier GetSupplier([FromODataUri] int key) 
{ 
    Product product = _context.Products.FirstOrDefault(p => p.ID == key); 
    if (product == null) 
    { 
     throw new HttpResponseException(HttpStatusCode.NotFound); 
    } 
    return product.Supplier; 
} 

的关键参数是该产品的密钥。该方法返回相关实体 - 在这种情况下为供应商实例。方法名称和参数名称都很重要。通常,如果导航属性名为“X”,则需要添加名为“GetX”的方法。该方法必须采用与父键的数据类型匹配的名为“key”的参数。

在关键参数中包含[FromOdataUri]属性也很重要。此属性告诉Web API在解析请求URI中的密钥时使用OData语法规则。