EF 6添加后获取实体

时间:2019-07-15 12:45:51

标签: c# entity-framework

我在.NET MVC应用程序中使用EF 6。我有这些课:

View

要添加的代码:

public class Member 
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int FactoryID { get; set; }
    public Factory Factory { get; set; }
}

public class Factory
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Member> Members { get; set; }
}

获取代码:

var newMember = new Member();
newMember.Name = 1;
newMember.FactoryID = 2;
context.Members.Add(newMember);
context.SaveChanges();

因此,当我在一个API调用中添加var member = context.Members.SingleOrDefault(x => x.ID == id); var factory = member.Factory; ,然后在另一个API调用中获得Member时,便定义了Member

当我尝试添加后立即获得Member.Factory时,则MemberMember.Factory

这是什么原因?以及如何解决?

1 个答案:

答案 0 :(得分:0)

之所以有时会起作用,而不是其他原因,是因为当您通过ID引用实体时,EF会提供它知道的相关实体。如果启用了延迟加载,EF将转到数据库以拉回它不知道的任何相关实体。不过,在序列化响应时,延迟加载会导致性能问题或循环引用错误。

例如,关闭延迟加载:

如果我做类似的事情:

using (var context = new MyContext())
{
   var member = new Member
   {
      FactoryId = 3;
      // ... 
   }
   context.Members.Add(member);
   context.SaveChanges();
   return member;
}

返回的成员的“ Factory”引用将为#null,因为该EF上下文不知道实际的Factory ID 3是什么。如果存在工厂ID#3的数据记录,但是上下文不知道该插入,则插入将成功。

如果在另一个示例中,我做这样的事情:

using (var context = new MyContext())
{ 
   // Call some code using this context that results in the following running...
   var factory = context.Factories.Single(x => x.FactoryId == 3);
   // more code...

   var member = new Member
   {
      FactoryId = 3;
      // ... 
   }
   context.Members.Add(member);
   context.SaveChanges();
   return member;
}

在这种情况下,EF将与成员一起返回Factory#3,因为上下文实例知道Factory#3。保存成员后,已知引用将自动关联。

上面的示例在using块中使用了DbContext,这使情况看起来很明显,但是,使用IoC容器将DbContext限定为请求的代码的代码,例如,对于任何给定的代码来说,它可能都不太清晰可以调用各种方法等方法来找出DbContext可能或不知道的实体。

在处理引用时,您想返回有关实体及其引用的详细信息,或者以下代码将从访问引用中受益,我的典型建议是设置引用,而不是实体中的FK。这样,您可以确保所创建的实体处于完整且适合目的的状态。

例如:

using (var context = new MyContext())
{ 
   var factory = context.Factories.Single(x => x.FactoryId == factoryId); 
   var member = new Member
   {
      Factory = factory;
      // ... 
   }
   context.Members.Add(member);
   context.SaveChanges();
   return member;
}

我避免在我的实体中完全暴露FK以强制使用引用,并使用影子属性(EFCore)和映射(EF6)确保我的实体中不可访问FK。 FK的麻烦在于,当编辑同时具有引用和FK列的实体时,有两个事实来源。更新Factory是否会更改工厂参考,还是会更新FactoryId?如果我有一个指向工厂ID 3的工厂引用,但是我将Member的FactoryId更改为4怎么办?某些代码可能取决于FK,而另一些代码可能会进入出厂参考。

显式使用引用意味着在那时声明相关实体(而不是等待对SaveChanges的任何数量的FK违反)。它将使用上下文已加载的所有已加载引用,或在需要时转到数据库。

我在引用上确实使用FK的地方是用于批量操作,在这些操作中我只想尽快更新或插入大量信息。在这些情况下,我将使用带有裸露骨骼的简单上下文定义和FK,而没有创建,设置FK和保存的引用。无需返回完整的数据和引用。