首页 文章

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

提问于
浏览
6

语境:

  • Code First,Entity Framework 4.3.1;

  • 用户----主题, 1 to Many 关系;

  • User with public virtual ICollection<Topic> CreatedTopics 导航属性(延迟加载);

  • Topic with public virtual User Creator Navigation Property;

  • DataServiceController : DbDataController<DefaultDbContext> ,Web API beta,ASP.NET MVC 4 Beta,单页应用程序;

  • System.Json用于Json序列化;

  • Web API操作:

public IQueryable<Topic> GetTopics()
{
    // return DbContext.Topics;                   // OK
    return DbContext.Topics.Include("Creator");   //With Exception
}
  • 结果: "an unhandled microsoft .net framework exception occurred in w3wp.exe"

这里的问题似乎是:我不应该 Add Navigation Property in both Entities (导致循环引用?),如果我删除 User 类中的 CreatedTopics 导航属性,它将再次正常 .

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

  • 如何在 1 to Many 关系的情况下处理导航属性;

  • 此外, Many to Many 关系怎么样,我必须把它分成两个 1 to Many 关系;

  • 使用导航属性的最佳实践和注意事项是什么?

我看过很多相关的帖子,但还不够清楚:(,

谢谢你的帮助!

院长

1 回答

  • 9

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

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

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

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

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

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

相关问题