实体框架懒惰加载错误行为

本文关键字:错误 加载 框架 实体 | 更新日期: 2023-09-27 18:22:26

在我的控制器操作中,我试图将新图像添加到数据库中。图像需要与设备相关联,设备与用户相关联。

所以我有了我的实体类:

public class Image
{
   public int Id { get; set; }
   public string Url { get; set; }
   [Required]
   public virtual Device { get; set; }
}
public class Device
{
   public int Id { get; set; }
   public string Name { get; set; }
   [Required]
   public virtual User { get; set; }
}
public class User
{
   public int Id { get; set; }
   public string Login{ get; set; }
   public virtual ICollection<Device> Devices { get; set; }
   [Required]
   [DataType(DataType.EmailAddress)]
   public virtual string Email{ get; set; }
}

现在,当我尝试添加这样的新图像时:

var image = new Image(); 
image.Device = Db.DbSet<Device>().Find(1); 
Db.DbSet<Image>().Add(image); 
Db.DbSet<Image>().SaveChanges();

问题是,当我使用这个Find来填充现有设备时(用户和所有属性都设置正确),我在设备中没有得到正确填充的user属性。这就像懒惰的加载没有起作用。有一个User对象的实例,但它的id设置为0,并且所有其他字段都设置为默认值。

我把所有的导航属性都设置为虚拟的,懒惰加载在我的其他实体上也可以正常工作,所以它肯定不会关闭或其他什么。

有趣的是,当我在添加图像之前更改代码和比较时,它会加载用户并正常工作:

if (AuthenticationHelper.CurrentUser != image.Device.User)
    return null;

就像它在这个时刻设法加载用户一样。如果我们将此比较顺序更改为遵循image.Device.User != AuthenticationHelper.CurrentUser,它将不再起作用。

你知道这是怎么回事吗?

实体框架懒惰加载错误行为

我认为延迟加载是正确的。您正在查找ID为1的Device,然后在不访问Device上的User属性的情况下将其分配给图像。如果Device模型上没有显式外键UserID属性,则永远不会访问User属性,因此永远不会有值,并插入null。

尝试将UserID(或者User_ID,如果你想保持实体框架的约定)添加到你的Device模型中,你的代码应该可以工作了。

该问题可能是由在实体默认构造函数中实例化引用导航属性(Device.User)引起的。加载和保存实体时会产生副作用和意外行为。其他例子就在这里。

当谈到"懒惰加载"时,实体框架与LINQ to SQL或NHibernate不太一样。在EF中,设计决策是为了确保开发人员准确地知道他们何时访问资源,例如数据库。因此,Lazy Loading不允许"自动"重新查询数据库;相反,它提供了资源的"延迟"加载。EF永远不会在开发人员没有意识到的情况下在稍后启动辅助数据库调用;相反,开发人员应该对.Load()方法进行显式调用以启动辅助调用,或者通过.Include()急切地加载延迟资源。