导航属性在延迟加载打开时适当加载

问题描述 投票:0回答:2

看起来像我的导航属性在打开延迟加载时急切加载。我有这样的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 = "[email protected]",
                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"
            });
        });

    }
}

我不希望加载导航属性“用户”,除非我使用“包含”。但它会自动加载。在我的启动中,我有这样的配置。

       services.AddDbContext<BBBankContext>(
b => b.UseSqlServer(connection)
        .UseLazyLoadingProxies(false)  //Install-Package Microsoft.EntityFrameworkCore.Proxies -Version 3.1.1

        );

实体看起来像这样

    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 enum AccountStatus
{
    Active = 0,
    InActive = 1
}

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

 public class BaseEntity
{
    [Key]
    public string Id { get; set; }
}

enter image description here

因为延迟加载设置为false。我期望“用户”为空

entity-framework entity-framework-core lazy-loading
2个回答
0
投票

下面是Microsoft EF Core instructions,这是我的处理方式(我另外将Key属性类型更改为Guid):

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 = "[email protected]",
                    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"
                });
            });
        }
    }

您可以找到工作资料库at GitHub


0
投票

即使禁用了延迟加载,如果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代表dbContext已加载并跟踪了父ID#2。在DbContext的生存期内,这可能发生在调用之前的任何地方,尤其是生存期范围遍及整个请求的情况。当我们以后去检索我们的子级,并假设懒惰加载已关闭并且我们不希望加载其父级时,您会发现,子级ID#1的父级引用为#null,但DbContext会将父级#2与孩子#2。当上下文填充“子级2”引用时,它看到与父级2的关联,并希望“父级ID 2”,它是本地跟踪缓存知道“父级2”,因此该引用自动填充。

如果改为junk行:

var junk = context.Parents.AsNoTracking().Single(x => x.ParentId == 2);

然后,子级2的父级引用也将为#null,因为DbContext不会跟踪该父级引用。

随着应用程序的成熟以及新代码的引入或重构,这可能导致各种古怪的行为。只需要有人添加AsNoTracking()作为“性能优化”,并且以前引用某些内容的某些行为现在已经失效。

作为避免复杂情况的一般规则,我的建议是不要返回超出产生它们的DbContext范围的实体,而应依靠ViewModels或DTO来表示要传递给视图或返回给API的数据消费者,而不是为此目的选择性地填充实体。实体应始终反映完整的数据状态,方法是填充其所有数据或访问所有数据(通过代理)。当不完整的实体被传递时,最终它们进入期望完整实体的方法(基于方法签名),这在假定数据是完整的但该实体的来源被遗弃的情况下导致了问题。

© www.soinside.com 2019 - 2024. All rights reserved.