首页 > 解决方案 > LazyLoading 在 EFCore 中的行为不符合预期

问题描述

这里有 2 个(最小化的类):

    [Index(nameof(Name), IsUnique = true)]
    public partial class ParticipantList
    {
        public ParticipantList()
        {
            Emails = new HashSet<Email>();
        }

        [Key]
        [Column("id")]
        public long Id { get; set; }
        //...
        [InverseProperty(nameof(Email.ParticipantList))]
        public virtual ICollection<Email> Emails { get ; set; }
    }

    public partial class Email
    {
        [Key]
        [Column("id", TypeName = "integer")]
        public long Id { get; set; }
        [Column("participant_list_id", TypeName = "integer")]
        public long? ParticipantListId { get; set; }
        /...
        [ForeignKey(nameof(ParticipantListId))]
        [InverseProperty("Emails")]
        public virtual ParticipantList ParticipantList { get; set; }

    }

DbContextOnConfiguring方法包含:

                optionsBuilder
                    .UseLazyLoadingProxies()
                    .UseSqlite(...);

DBContextOnModelCreating方法包含:

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Email>(entity =>
            {
                entity.HasOne(d => d.ParticipantList)
                    .WithMany(p => p.Emails)
                    .HasForeignKey(d => d.ParticipantListId)
                    .OnDelete(DeleteBehavior.ClientSetNull);
            });

这是有效的:

var email = _db.Emails.Find(1);
// email.ParticipantList (this lazy loads just fine).

什么不起作用:

var plist = _db.ParticipantLists.Find(1);
// plist.Emails.Count() == 0  (this doesn't lazy load at all)
// plist.Emails.Count == 0    (again no lazy loading)
// plist.Emails.ToList()      (empty list, no lazy loading)

我应该在这里插入一个关于 Count() 和 Count 在这里具有不同含义的愚蠢之处。我的意思是,说真的,谁会在代码审查期间发现这一点????

这很可能是由于:

        public ParticipantList()
        {
            Emails = new HashSet<Email>();
        }

这是由 ef-scaffold 应用程序创建的。我的意思是它是有道理的,HashSet 是空的,但似乎模型应该覆盖对 HashSet 的访问并进行延迟加载。

问题是,如果你删除它:

        public ParticipantList()
        {
            // Emails = new HashSet<Email>();
        }

然后调用此代码:

// plist.Emails.Count() == 0  (Now you get a null reference exception 
//                             because guess what:  Emails is not initialized!)
// plist.Emails.ToList()      (Also gives a null reference exception)
// plist.Emails.Count == 0    (Again, a null reference exception)

文档显示了这样的代码(请注意,在https://docs.microsoft.com/en-us/ef/core/querying/related-data/lazy的示例中未初始化 Posts ):

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public virtual Blog Blog { get; set; }
}

据称这将延迟加载博客中的帖子。但是,当我遵循该模式并删除初始化电子邮件/帖子的 ctor 时,我得到一个空引用异常。

增加神秘/疯狂的是:

var email = _db.Emails.Find(1);
var plist = _db.ParticipantLists.Find(1);
// plist.Emails.Count() == 1 (It knows about the relation and added it to 
//                            the Emails HashSet on the ParticipantList!)

那么,我如何将电子邮件发送到 LazyLoad。我知道 1 + N 问题,我并不担心这方面,但我希望模型在被请求时加载。

标签: c#entity-framework-core

解决方案


推荐阅读