Свойство Navigation Eagerly загружается при включенной отложенной загрузке - PullRequest
0 голосов
/ 09 февраля 2020

Похоже, что мое свойство навигации загружается, когда включена отложенная загрузка. У меня есть настройка 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"
            });
        });

    }
}

Я не хочу, чтобы свойство навигации «Пользователь» загружалось, если я не использую «Включить». но это автоматически загружается. в моем стартапе у меня есть такая конфигурация загрузка установлена ​​в ложь. я ожидаю, что "пользователь" будет нулевым

Ответы [ 2 ]

0 голосов
/ 10 февраля 2020

Даже при отключенной отложенной загрузке, если DbContext уже отслеживает сущность, на которую вы ссылаетесь, эта ссылка будет заполнена автоматически.

Например, если у меня есть 2 записи Parent, каждая из которых содержит запись Child:

Parent 1 => Child 1

Parent 2 => Child 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, имеющий загружен и отслеживание родительского идентификатора № 2. В течение срока службы DbContext это может происходить в любом месте до нашего вызова, особенно если время жизни превышает весь запрос. Когда мы позже go найдем наших детей и предположим, что отложенная загрузка отключена, и мы не стремимся загружать их родителей, вы обнаружите, что родительская ссылка Child ID # 1 будет #null, но DbContext будет ассоциировать Parent # 2 с ребенком № 2. Когда контекст заполняет ссылку Child # 2, он видит связь с parent и хочет Parent ID # 2, его локальный кеш отслеживания знает о Parent # 2, поэтому ссылка заполняется автоматически.

Если junk вместо этого была строка:

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

, тогда родительская ссылка дочернего элемента # 2 также была бы #null, поскольку DbContext не отслеживал бы эту родительскую ссылку.

Это может привести ко всем видам причудливое поведение по мере того, как приложения развиваются, и новый код вводится или пересматривается. Все, что нужно, это добавить кого-то AsNoTracking() в качестве «оптимизации производительности», а какое-то поведение, которое ранее ссылалось на что-то, теперь не работает.

Как правило, чтобы избежать осложнений, я рекомендую никогда вернуть Entities за пределы DbContext, который их породил, и вместо этого полагаться на ViewModels или DTO для представления данных, которые вы хотите передать в представление или вернуть потребителю API, вместо того, чтобы пытаться выборочно заполнять объекты для этой цели. Сущность всегда должна отражать полное состояние данных, либо заполнив все свои данные, либо все данные доступны (через прокси). Когда незавершенные сущности передаются, в конечном итоге они попадают в методы, которые ожидают завершенные сущности (основанные на сигнатуре метода), и это приводит к проблемам, когда предполагается, что данные являются полными, но источник этой сущности не заполнен.

0 голосов
/ 09 февраля 2020

Следуя инструкциям Microsoft EF Core , вот как я это сделаю (я дополнительно изменил тип свойства 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 = "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"
                });
            });
        }
    }

Вы можете найти рабочие репозиторий на GitHub

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...