【问题标题】:Entity framework Lazy Loading incorrect behaviour实体框架延迟加载不正确的行为
【发布时间】:2023-03-09 07:57:01
【问题描述】:

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

所以我有我的实体类:

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 对象的实例,但它的 id 设置为 0,并且所有其他字段都设置为其默认值。

我将所有导航属性设置为虚拟,延迟加载在我的其他实体上也可以正常工作,因此它绝对没有关闭或其他什么。

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

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

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

有什么想法吗?

【问题讨论】:

  • 您的Device 类是否具有实例化User 属性的默认构造函数?如果是,请尝试在没有实例化的情况下它是否可以正常工作。
  • @Slauma - 事实证明你是对的!请添加答案,以便我接受。

标签: c# asp.net-mvc entity-framework entity-framework-5 lazy-loading


【解决方案1】:

我认为延迟加载工作正常。您将找到 ID 为 1 的 Device,然后将其分配给图像,而无需访问 Device 上的 User 属性。如果您的 Device 模型上没有显式外键 UserID 属性,则永远不会访问 User 属性,因此永远不会有值,并且插入 null。

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

【讨论】:

  • 好的,它不加载User 可能是一个正确的行为,但是如果它知道这是一个db 代理并且它是从db 中获取的,它也应该避免验证这个属性。即使它尝试验证 - 为什么在验证器访问 User 时不加载它?
  • 另外,我只是尝试在 Add 方法之前调用 image.Device.User.Email.ToString(),但它仍然没有加载它 - 它只是抛出 Null Ref 异常,因为 Email 仍然是 null...
  • @ŁukaszW.pl 我会问愚蠢的问题,数据库中有 ID 为 1 的设备吗?
  • 是的。无论如何,事实证明斯劳马是对的。这是由于在实体默认构造函数中实例化导航属性引起的。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    在“延迟加载”方面,实体框架与 LINQ to SQL 或 NHibernate 并不完全相同。在 EF 中,设计决策是确保开发人员准确地知道他们何时访问资源,例如数据库。因此,延迟加载不会启用“自动”数据库重新查询;相反,它提供了资源的“延迟”加载。 EF 永远不会在开发人员不知道的情况下在以后启动辅助数据库调用;相反,开发人员应该显式调用.Load() 方法来启动辅助调用,或者通过.Include() 急切地加载延迟资源。

    【讨论】:

    • 不正确 - LoadIncludecontext.ContextOptions.LazyLoadingEnabled 设置为 false 时使用。否则它应该在访问时加载导航属性。
    猜你喜欢
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多