首先在实体框架代码中使用导航属性

时间:2012-07-03 16:33:49

标签: entity-framework-4 ef-code-first asp.net-web-api navigation-properties

上下文:

  • Code First,Entity Framework 4.3.1;
  • 用户----主题, 1到多个关系;
  • User public virtual ICollection<Topic> CreatedTopics导航属性(延迟加载);
  • Topicpublic virtual User Creator导航属性;
  • DataServiceController : DbDataController<DefaultDbContext>,Web API测试版,ASP.NET MVC 4 Beta,单页应用程序;
  • System.Json for Json序列化;
  • Web API操作:

    public IQueryable<Topic> GetTopics()
    {
        // return DbContext.Topics;                   // OK
        return DbContext.Topics.Include("Creator");   //With Exception
    }
    
  • 结果:“w3wp.exe中发生了未处理的微软.net框架异常”

这里的问题似乎是:我不应该在两个实体中添加导航属性(导致循环引用?),如果我删除CreatedTopics中的User导航属性} Class,再次没问题。

所以,在上面列出的类似上下文中,以下是我的问题:

  1. 如何在 1到多关系的情况下处理导航属性;
  2. 此外,多对多关系如何,我必须将其分为两个 1到多个关系;
  3. 使用导航属性的最佳做法和注意事项是什么?
  4. 我读了很多相关的帖子,但还不够清楚:(,

    感谢您的帮助!

    迪安

1 个答案:

答案 0 :(得分:9)

这不是代码优先或EF的问题 - 这是序列化的问题。用于将对象图转换为Web API消息中传递的某些表示形式的序列化程序默认情况下无法使用循环引用。根据您要使用的消息格式,Web API默认使用不同的序列化程序 - here更多地是关于Web API使用的默认序列化程序以及如何更改它的方式。以下文本假设您正在使用DataContractJsonSerializerDataContractSerializer(应该是XML序列化的默认设置),但JSON.NET也是如此(对于JSON序列化应该是默认的 - JSON序列化可以切换为DataContractJsonSerializer但默认的序列化程序更好。)

那你可以做什么?您可以通过使用DataContract(IsReference = true)标记类以及每个带有DataMember属性的传递属性来告诉序列化程序它应该跟踪这些循环引用(请查看链接文章以了解如何使用JSON.NET实现它)。这将允许序列化器正确识别循环,并且序列化在理论上将成功。理论上因为这也要求不使用延迟加载。否则,您可以序列化比预期更多的数据(在某些灾难性情况下,它可能导致序列化数据库的整个内容)。

当您启用延迟加载序列化实体图时,您会对Topic及其Creator进行搜索,但序列化也会访问CreatedTopics property =&gt;所有相关主题都是延迟加载并通过序列化处理,序列化继续访问所有新加载主题的Creator!此过程将继续,直到没有其他对象延迟加载。因此,在序列化实体时不应使用延迟加载。

其他选项是从序列化中排除反向引用。您只需要序列化Creator。您无需序列化CreatedTopics,因此您可以使用IgnoreDataMember属性(JsonIgnore为JSON.NET标记)该属性。问题是,如果您还有用于返回User所有CreateTopics的Web API操作,则由于该属性,这将无效。

最后一个选项不使用实体。此选项通常用于Web服务,您可以在其中创建满足特定操作要求的特殊DTO对象,并处理操作中实体和DTO之间的转换(可以借助AutoMapper等工具)。

处理一对一,一对多或多对多关系之间没有区别。如果双方都有导航属性,则必须始终处理此问题。