实体框架 急于加载和延迟加载

本文关键字:加载 延迟加载 框架 于加载 实体 | 更新日期: 2023-09-27 18:35:25

试图找出实体框架中延迟加载和渴望加载之间的区别。假设我有以下型号:

public interface IBaseEntityObject 
{
    public int Id {get; set;}
}

public abstract class BaseEntityObject : IBaseEntityObject
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id {get; set;}
}

public class Folder : BaseEntityObject
{   
    [DataMember]
    public string Name {get; set;}
    [DataMember]
    public virtual List<Letter> Letters {get; set;} 
}

public abstract class Letter : BaseEntityObject
{   
    [DataMember]
    public string Title {get; set;}
    [DataMember]
    public string Content {get; set;}
    public virtual Folder Folder {get; set;}
    [DataMember]
    public int FolderId {get; set;}
    [DataMember]
    public DateTime CreationDate {get; set;}
}
public class OutgoingLetter : Letter
{
    // .. OutgoingLetter properties
}
public class ReceviedLetter : Letter
{
    // .. ReceviedLetter properties
}

public class MyDbContext : DbContext
{
    public DbSet<Folder> Folders {get; set;}
    public DbSet<Letter> Letters {get; set;}

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        // Folder <-> Letters       
        modelBuilder.Entity<Letter>()
        .HasRequired(t => t.Folder)
        .WithMany(f => f.Letters)
        .HasForeignKey(t => t.FolderId)
        .WillCascadeOnDelete(true);
    }
}

每当我从数据库中询问文件夹时,它的主要目的是访问其中的字母。因此,如果我从一开始就加载它而不是在访问 Letters 属性时进行另一个数据库调用,那将是最好的,我是否正确?

我已经读到禁用延迟加载是通过在 ctor 中配置它来完成的,方法是将 EnableLazyLoading 属性设置为 false 并从字母列表中删除虚拟关键字。

如果我在请求文件夹并保持延迟加载启用时只使用 Include(x => x.Lettters),会有什么区别?启用延迟加载时不能使用包含?

此外,Letter 模型中保存的 Folder 属性与延迟加载之间是否存在任何关系?我在索要信件时不使用文件夹,但我见过的大多数模型都包含一对多关系中的父亲属性,我真的不明白为什么。

谢谢!

实体框架 急于加载和延迟加载

每当我从数据库中询问文件夹时,它的主要目的是访问其中的字母。因此,如果我从一开始就加载它而不是在访问 Letters 属性时进行另一个数据库调用,那将是最好的,我是否正确?

是的,正确。

我已经读到禁用延迟加载是通过在 ctor 中配置它来完成的,方法是将 EnableLazyLoading 属性设置为 false 并从字母列表中删除虚拟关键字。

如果您不希望延迟加载某个属性,请删除 virtual 关键字。如果有时需要它,有时不需要,请在代码中创建新上下文时禁用延迟加载。

如果我在请求文件夹并保持延迟加载启用时只使用 Include(x => x.Lettters),会有什么区别?启用延迟加载时不能使用包含?

它们对彼此没有影响。如果未包含字母,并且尝试访问该属性,EF 将再次调用 db 以获取它们(延迟加载),如果包含它们,则它们可用,并且不会对数据库进行额外调用。

此外,Letter 模型中保存的 Folder 属性与延迟加载之间是否存在任何关系?我在索要信件时不使用文件夹,但我见过的大多数模型都包含一对多关系中的父亲属性,我真的不明白为什么。

在大多数示例中,导航属性以两种方式定义,但如果永远不需要从信件中获取文件夹,则不在字母模型中定义该属性是完全有意义的。

我已经读到禁用延迟加载是通过在 通过将启用延迟加载属性设置为 false 和 从字母列表中删除虚拟关键字

博特不聪明。这相当于将电池从汽车中取出只是为了关闭发动机。

延迟加载启用并不意味着它被使用,与虚拟相同

如果我只使用 Include(x => x.Lettters) 会有什么区别 每当我要求一个文件夹并保持启用延迟加载时?

后者将能够使用延迟加载(破坏后你不能)。

启用延迟加载时不能使用包含?

谁说的?它完全可以 - 在这种情况下,对于已经包含的元素,延迟加载根本不会发生,这使您可以根据具体情况自由选择延迟加载或不延迟加载。

您也可以在启用延迟加载的情况下使用"包括"。不使用 Include 会使代码更清晰,因此通常我仅在遇到性能问题时才使用 Include。
此外,导航可能会在项目生命周期内发生变化,因此对于延迟加载,您无需记住它。
而且,您不能在序列化期间使用延迟加载,否则您可能会序列化所有数据库。

仅供参考,Include 也经常生成非常丑陋的查询(但我从未遇到过性能问题)。

关于父属性仅用于导航目的(即,您可以从信件导航到文件夹,然后导航到文件夹的字母)。