为什么我的oData服务(实体框架)不允许导航属性

时间:2011-10-04 01:42:06

标签: wcf frameworks entity odata

如果我在Web项目中使用我的实体模型,我可以很好地导航到1- * 1-0.1导航属性...但是当我在我的oData服务中通过LinqPad加载完全相同的对象时,nav属性始终为null

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

如果我加载fiddler并运行查询http://odata.site.com/Service1.svc/usda_FOOD_DES(1001)/usda_ABBREV

...它返回正确的结果

谢谢, 史蒂夫

2 个答案:

答案 0 :(得分:4)

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

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

原因是与Entity Framework的导航属性不同,当您访问OData实体的属性时,它不会自动返回到数据源并检索任何尚未存在的数据。因此,当您从OData Feed中检索实体时,默认情况下它不包含链接的实体,因此您可以获得一对多或多对多导航属性的空IEnumerable<T>或单实体导航属性为null。 / p>

您希望上述查询转换为:

  

的http; // odata.sample.com/MyODataFeed.svc/Customers(1)/订单

哪个会返回所有订单,而是转换为此(要在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)$扩大=订单&安培; $选择=订单

我不明白为什么这根本就没有翻译成/ Customers(1)/ Orders。在任何情况下,它都将订单列表放在一个不需要的包装器类中,这可能非常烦人,但它确实有效,而且它是我能够检索到导航属性内容的最接近的。

我更喜欢的方法是包括每个客户的所有订单,如下所示:

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

这会产生以下查询:

  

的http; // odata.sample.com/MyODataFeed.svc/Customers(1)$扩大=订单

这样可行,但缺点是包含我们可能不需要的所有客户详细信息。此外,.Expand(...)的字符串是有问题的 - 它的类型很弱,所以它不会被编译器验证(提防拼写错误),并非所有重构工具都会重构它,找到所有用法该属性不会在搜索结果中包含该字符串等。

答案 1 :(得分:0)

来自http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/working-with-entity-relations的最新v4 Asp.Net 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;
}

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

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