首页 > 解决方案 > EF 6 添加后获取实体

问题描述

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

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

获取代码:

var member = context.Members.SingleOrDefault(x => x.ID == id);
var factory = member.Factory;

因此,当我添加Member一个 API 调用时,然后定义Member另一个 API 调用。Member.Factory

当我尝试Member添加后立即获取时,Member.Factory就是NULL.

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

标签: c#entity-framework

解决方案


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

例如,关闭延迟加载:

如果我这样做:

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

返回的成员的“工厂”引用将为#null,因为该 EF 上下文不知道工厂 ID 3 实际是什么。如果存在 Factory 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 列的实体时,有 2 个事实来源。更新工厂会更改工厂引用,还是更新 FactoryId?如果我有一个指向 Factory ID 3 的 Factory 引用,但我将 Member 上的 FactoryId 更改为 4,该怎么办?一些代码可能取决于 FK,而其他代码可能会转到工厂参考。

显式使用引用意味着相关实体在该点被断言(而不是在 SaveChanges 上等待任意数量的 FK 违规)。它将使用上下文已加载的任何已加载引用,或在需要时转到数据库。

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


推荐阅读