Web API空导航属性

时间:2014-05-06 15:33:11

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

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

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 by Person.Name = PersonDetails.FullName但实体框架6确实处理它并生成类似SQL的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记录都为null,这没关系。

但似乎OData Formatter在Person.Name为null时遇到问题。我的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记录上可能为null。

我能看到的唯一前进方法是使用HasNavigationPropertyLink,而不是像上面那样以标准方式构建ProductDetails。

有人能就我该做什么给我任何建议吗?

3 个答案:

答案 0 :(得分: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();
        }
    }

答案 1 :(得分:-1)

试试这段代码:

   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);

答案 2 :(得分:-1)

这对我有用:

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);
}