如何防止EF7急切地修复导航属性?

时间:2016-02-16 17:02:24

标签: entity-framework-core

我在Web应用程序中使用EF7时遇到问题,我可以使用它来帮助您。我目前正在使用EF7 RC1。

以下是一些说明我问题的模型。

public class Contact
{
    public Guid Id { get; set; }

    public string Desc { get; set; }
    public ContactType ContactType { get; set; }
}

ContactType

public class ContactType
{
    public Guid Id { get; set; }
    public string Desc { get; set; }

    public ICollection<Contact> Contacts { get; set; }
}

这些模型通过Fluent API相关,如下所示:

modelBuilder.Entity<Contact>(entity => {
     // abridged for clarity

     entity
        .HasOne(c => c.ContactType)
        .WithMany(ct => ct.Contacts)
        .IsRequired();                
});

我的需求是能够从加载了ContactType属性的数据库中检索Contact实体的集合。 EF使这很容易:

using(var context = new MyDbContext()) {
    var contacts = await context
        .Contacts
        .Include(c => c.ContactTypes)
        .Where(/* some search criteria */)
        .ToListAsync();
}

问题在于,在加载Contact实体的ContactType属性时(由于在查询中调用.Include()而发生),EF还有助于加载每个ContactType实体的Contacts属性,从而产生无限链指向ContactTypes和ContactTypes指向Contacts的Contacts。我理解为什么这是默认行为,并且在许多情况下它很有用,但我的需求是将这些实体序列化为JSON并将它们发送到客户端 - 这是一个只读的情况。

我希望的行为是EF返回一个Contact集合,其中的Contacts(非null)ContactType属性的Contacts属性设置为null。 EF可以做什么?有没有办法最终得到对象图我想要手动清空我不想填充的属性?

我尝试过的事情:

  • 将.AsNoTracking()附加到EF查询(似乎没有停止 ContactType实体的Contacts属性被加载)
  • 告诉Json.NET不要序列化无限引用循环(这是 要求在序列化期间避免无限递归,但仍然如此 导致大量额外数据被序列化)

1 个答案:

答案 0 :(得分:5)

你无法避免EF加载ContactType.Contacts集合,因为它实际上没有加载它,而是用加载的Contact实例填充集合。 这就是使用AsNoTracking没有效果的原因,因为这不是延迟加载和ChangeTracker的问题。

您有三种可能的解决方案:

  1. 使用Json.NET ReferenceLoopHandling = ReferenceLoopHandling.Ignore,但正如您所说,它将生成大量不必要的数据,因为您将获得每个ContactType的联系人集合
  2. 在ContactType.Contacts上使用[JsonIgnore]属性,因此序列化程序将忽略它。但它总是会忽略它,我不知道你是否在其他情况下需要它
  3. 定义DTO,使用类似Automapper的内容来映射数据(不使用Contacts集合)并序列化
  4. 我更喜欢第3个选项,因为我不喜欢将域模型对象发送到客户端,并且它避免向与域无关的域模型添加属性。