【问题标题】:Web API Null Navigation PropertyWeb API 空导航属性
【发布时间】:2014-05-06 15:33:10
【问题描述】:

当我尝试在模型中展开对象的导航属性时出现错误。

eg. /odata/Products?$expand=ProductDetails

我收到以下错误:

No NavigationLink factory was found for the navigation property 'ProductDetails' from entity type 'ProductModels.Models.Product' on entity set 'Products'. Try calling HasNavigationPropertyLink on the EntitySetConfiguration.

参数名称:navigationProperty

我的模型如下所示:

public class Person
{
    public int Id { get; set; }

    public string Name { get; set; }
    [ForeignKey("Name")]
    public PersonDetails PersonDetails { get; set; }
}

public class PersonDetails
{
    [Key]
    public string FullName { get; set; }

    public int Age { get; set; }

}

这是一对零/一的关系,您可以看到我的模型有点奇怪,因为 PersonDetails 通过 Person.Name = PersonDetails.FullName 链接到 Person 但 Entity Framework 6 确实处理它并生成类似 SQL以下:

SELECT 
[Extent1].[Id] AS [Id], 
N'f4243347-5b4c-4790-a07d-e8beb80bea72' AS [C1], 
[Extent1].[Name] AS [Name], 
N'PersonDetails' AS [C2], 
N'f4243347-5b4c-4790-a07d-e8beb80bea72' AS [C3], 
[Extent2].[FullName] AS [FullName], 
[Extent2].[Age] AS [Age], 
CASE WHEN ([Extent1].[Name] IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C4]
FROM  [Persons] AS [Extent1]
LEFT OUTER JOIN [PersonDetails] AS [Extent2] ON [Extent1].[Name] = [Extent2].[FullName]

而且在结果中,很多 ProductDetails 记录都是空的,没关系。

但在 Person.Name 为空的情况下,OData 格式化程序似乎存在问题。我的 ProductsContext 中有以下设置:

public System.Data.Entity.DbSet<Product> Products { get; set;

还有这个 ODataConventionModelBuilder:

builder.EntitySet<Vehicle>("Products");

我没有 ProductDetails 控制器,因为我不想直接访问它,只能通过 Products 控制器。

如果我添加一个:

builder.EntitySet<Vehicle>("ProductDetails");

然后我得到一个:

The EDM instance of type '[ProductModels.Models.ProductDetails Nullable=True]' is missing the property 'FullName'.

这是有道理的,因为 FullName 在 ProductDetails 记录中很可能为空。

我能看到的唯一前进方法是使用 HasNavigationPropertyLink 而不是按照上面的标准方式构建 ProductDetails。

谁能给我任何关于我应该做什么的建议?

【问题讨论】:

    标签: c# odata asp.net-web-api2


    【解决方案1】:

    将实体条目添加到ODataConfig.cs,如下所示。

    builder.EntitySet<EntityName>(typeof(EntityName).Name);
    

    整个代码会是这样的

    public static class ODataConfig
        {
            public static void Register(HttpConfiguration config)
            {
                ODataModelBuilder builder = new ODataConventionModelBuilder();
                builder.EntitySet<EntityName>(typeof(EntityName).Name);
                var model = builder.GetEdmModel();
                config.Routes.MapODataRoute("odata", "odata", model);
    
                config.EnableQuerySupport();
            }
        }
    

    【讨论】:

      【解决方案2】:

      试试这个代码 sn-p:

         var products=builder.EntitySet<Vehicle>("Products");
         products.HasNavigationPropertiesLink(
                      product.NavigationProperties,
                      (entityContext, navigationProperty) =>
                      {
                          object id;
                          entityContext.EdmObject.TryGetPropertyValue("ID", out id);
                          return new Uri(entityContext.Url.Link(ODataTestConstants.DefaultRouteName,
                      new
                      {
                          odataPath = entityContext.Url.CreateODataLink(
                              new EntitySetPathSegment(entityContext.NavigationSource.Name),
                              new KeyValuePathSegment(id.ToString()),
                              new NavigationPathSegment(navigationProperty))
                      }));
                      }, true);
      

      【讨论】:

      • 感谢您的回复。 product 似乎没有 NavigationProperties 的集合,但 product.EntityType 有。这是我应该使用的吗?我可以用任何东西替换 ODataTestConstants.DefaultRouteName 还是需要引用一些东西?我可以使用 Url.ODataLink 而不是 Url.CreateODataLink 吗?你能告诉我 entityContext.NavigationSource.Name 应该返回什么 - 我应该参考另一个库吗?
      • 添加一些关于代码如何工作的描述?并回复 cmets?请.. :)
      【解决方案3】:

      这对我有用:

      foreach (var navProp in products.EntityType.NavigationProperties)
                  {
       products.HasNavigationPropertyLink(
                 navprop,
                 (entityContext, navigationProperty) =>
                 {
                     object id;
                     entityContext.EdmObject.TryGetPropertyValue("ID", out id);
                     return new Uri(entityContext.Url.CreateODataLink(
                           new EntitySetPathSegment(navprop.Name),
                           new KeyValuePathSegment(id.ToString())
                           ));
                 }, false);
      }
      

      【讨论】:

      • 没有说明代码的作用?我尝试使用它 - 但没有 EntitySetPathSegment/KeyValuePathSegment 类的迹象。这是哪个版本的 OData?
      猜你喜欢
      • 1970-01-01
      • 2014-05-24
      • 1970-01-01
      • 1970-01-01
      • 2013-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-14
      相关资源
      最近更新 更多