我在.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
时,则Member
是Member.Factory
。
这是什么原因?以及如何解决?
答案 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和保存的引用。无需返回完整的数据和引用。