Entity framework 当启用延迟加载时,导航属性将立即加载

Entity framework 当启用延迟加载时,导航属性将立即加载,entity-framework,entity-framework-core,lazy-loading,Entity Framework,Entity Framework Core,Lazy Loading,当惰性加载打开时,我的导航属性似乎正在急切地加载。 我有这样一个DBContext设置 public class BBBankContext : DbContext { public BBBankContext(DbContextOptions<BBBankContext> options) : base(options) { } public DbSet<Account> Accounts { get; set; } p

当惰性加载打开时,我的导航属性似乎正在急切地加载。 我有这样一个DBContext设置

public class BBBankContext : DbContext
{
    public BBBankContext(DbContextOptions<BBBankContext> options)
        : base(options)
    { }

    public DbSet<Account> Accounts { get; set; }
    public DbSet<User> Users { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Account>(b =>
        {
            b.HasData(new Account
            {
                Id = "37846734-172e-4149-8cec-6f43d1eb3f60",
                AccountNumber = "0001-1001",
                AccountTitle = "Raas Masood",
                CurrentBalance = 2342.34,
                Email = "raasmasood@hotmail.com",
                PhoneNumber = "6096647000",
                AccountStatus = AccountStatus.Active

            });
            b.OwnsOne(e => e.User).HasData(new
            {
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                Id = Guid.NewGuid().ToString(),
                AuthID = Guid.NewGuid().ToString(),
                Name = "Raas Masood",
                ProfilePicUrl = "https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50"
            });
        });

    }
}

因为延迟加载被设置为false。我希望“user”为空

以下是我的做法(我另外将Key属性类型更改为Guid):

公共类基本实体
{
[关键]
公共Guid Id{get;set;}
}
公共类帐户:BaseEntity
{
公共字符串AccountNumber{get;set;}
公共字符串AccountTitle{get;set;}
公共双电流平衡{get;set;}
公共字符串电子邮件{get;set;}
公共字符串PhoneNumber{get;set;}
公共帐户状态{get;set;}
公共虚拟用户用户{get;set;}
公共Guid用户标识{get;set;}
}
公共类用户:BaseEntity
{
公共字符串AuthID{get;set;}
公共字符串名称{get;set;}
公共字符串ProfilePicUrl{get;set;}
公共虚拟帐户{get;set;}
}
公共枚举帐户状态
{
活动=0,
非活动=1
}
公共类BBBankContext:DbContext
{
公共BBBankContext(DbContextOptions)
:基本(选项)
{ }

公共DbSet

即使禁用了延迟加载,如果DbContext已经在跟踪您引用的实体,该引用也将自动填充

例如,如果我有两个父记录,每个记录包含一个子记录:

父1=>子1

父2=>子2

using (var context = new AppContext())
{
    var junk = context.Parents.Single(x => x.ParentId == 2);

    var children = context.Children.ToList();
    Assert.IsNull(children.Single(x => x.ChildId == 1).Parent);
    Assert.IsNotNull(children.Single(x => x.ChildId == 2).Parent);
}
这是一个非常粗糙的行为示例,但是
junk
表示加载并跟踪父ID的dbContext#2。在dbContext的生命周期中,这可能发生在调用之前的任何地方,特别是在生命周期范围覆盖整个请求的情况下。当我们稍后检索子对象时,并假设延迟加载如果禁用,并且我们不急于加载它们的父对象,您会发现子ID#1的父对象引用将为空,但DbContext将把父对象#2与子对象#2关联起来。当上下文填充子对象#2引用时,它会看到与父对象的关联,并需要父对象ID#2,它的本地跟踪缓存知道父对象#2,因此引用rence将自动填充

如果
垃圾
行改为:

var junk = context.Parents.AsNoTracking().Single(x => x.ParentId == 2);
那么,子#2的父引用也将为#null,因为DbContext不会跟踪该父引用

随着应用程序的成熟和新代码的引入或重新设计,这可能会导致各种奇怪的行为。只需要有人添加一个
AsNoTracking()
,作为“性能优化”,而一些以前引用过的行为现在已经破坏


作为避免复杂化的一般规则,我的建议是永远不要返回超出生成实体的DbContext范围的实体,而是依赖ViewModels或DTO来表示要传递给视图或返回给API使用者的数据,而不是尝试为此目的有选择地填充实体。实体应始终通过填充其所有数据或(通过代理)访问所有数据来反映完整的数据状态。当传递不完整的实体时,最终它们进入期望完整实体的方法(基于方法签名)当数据被认为是完整的,但实体的来源遗漏了数据时,这会导致问题。

延迟加载意味着导航属性一经调用就会自动加载。如果要使用“包含”,则必须使用快速加载而不是延迟加载,因此我设置了UseLazyLoadingProxies(false)这意味着当我加载导航属性时不应该加载。但它正在加载。我刚刚用image更新了问题。因为延迟加载被设置为false。我希望“user”为null尝试添加如下用户数据:
modelBuilder.Entity(b=>{b.HasData(新用户{AccountId=“37846734-172e-4149-8cec-6f43d1eb3f60”,Id=Guid.NewGuid().ToString(),AuthID=Guid.NewGuid().ToString(),Name=“Raas Masood”,ProfilePicUrl=”https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50"             })
现在当我运行时,用户为空,但是当我包含用户“return await DbSet.Include(“User”).tolistsync();”时,它仍然为空。DbSet设置为_context()”检测到不支持的可能对象循环。这可能是由于循环造成的,也可能是因为对象深度大于允许的最大深度32。“看起来模型结构中发生了一些循环现象。我创建了一个github存储库。工作起来很有魅力;-)在我的回答中,我为您链接了它。如果OData可以达到这个目的。我们只需返回IQueryable集合,其余的魔法将由OData在客户端完成。我们可以选择、包含和查询OData查询字符串中的所有内容。但我也明白了您的意思。我只是试图专注于查询优化,以便tabase到api是一次轻松的旅行。
public class BaseEntity
{
    [Key]
    public Guid Id { get; set; }
}

public class Account : BaseEntity
    {
        public string AccountNumber { get; set; }
        public string AccountTitle { get; set; }
        public double CurrentBalance { get; set; }
        public string Email { get; set; }
        public string PhoneNumber { get; set; }
        public AccountStatus AccountStatus { get; set; }
        public virtual User User { get; set; }
        public Guid UserId { get; set; }
    }

public class User : BaseEntity
    {
        public string AuthID { get; set; }
        public string Name { get; set; }
        public string ProfilePicUrl { get; set; }
        public virtual Account Account { get; set; }
    }

public enum AccountStatus
    {
        Active = 0,
        InActive = 1
    }

public class BBBankContext : DbContext
    {
        public BBBankContext(DbContextOptions<BBBankContext> options)
        : base(options)
        { }

        public DbSet<Account> Accounts { get; set; }
        public DbSet<User> Users { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Account>(b =>
            {
                b.HasData(new Account
                {
                    Id = Guid.Parse("37846734-172e-4149-8cec-6f43d1eb3f60"),
                    AccountNumber = "0001-1001",
                    AccountTitle = "Raas Masood",
                    CurrentBalance = 2342.34,
                    Email = "raasmasood@hotmail.com",
                    PhoneNumber = "6096647000",
                    AccountStatus = AccountStatus.Active,
                    UserId = Guid.Parse("24ce7f8a-cbeb-4b33-8a3d-952830b92d04")
                });

                b.HasOne(a => a.User)
                    .WithOne(u => u.Account)
                    .HasForeignKey<Account>(a => a.UserId);
            });

            modelBuilder.Entity<User>(b =>
            {
                b.HasData(new User
                {
                    Id = Guid.Parse("24ce7f8a-cbeb-4b33-8a3d-952830b92d04"),
                    AuthID = Guid.NewGuid().ToString(),
                    Name = "Raas Masood",
                    ProfilePicUrl = "https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50"
                });
            });
        }
    }
using (var context = new AppContext())
{
    var junk = context.Parents.Single(x => x.ParentId == 2);

    var children = context.Children.ToList();
    Assert.IsNull(children.Single(x => x.ChildId == 1).Parent);
    Assert.IsNotNull(children.Single(x => x.ChildId == 2).Parent);
}
var junk = context.Parents.AsNoTracking().Single(x => x.ParentId == 2);