EF Core возвращает нулевые отношения до прямого доступа

У меня есть несколько моделей, подобных приведенным ниже:

public class Mutant
{
    public long Id { get; set; }
    ...

    // Relations
    public long OriginalCodeId { get; set; }
    public virtual OriginalCode OriginalCode { get; set; }
    public int DifficultyLevelId { get; set; }
    public virtual DifficultyLevel DifficultyLevel { get; set; }
}

а также

public class OriginalCode
{
    public long Id { get; set; }
    ...

    // Relations
    public virtual List<Mutant> Mutants { get; set; }
    public virtual List<OriginalCodeInputParameter> OriginalCodeInputParameters { get; set; }
}

и в OnModelCreating DBContext я сделал такие отношения:

        modelBuilder.Entity<Mutant>()
            .HasOne(m => m.OriginalCode)
            .WithMany(oc => oc.Mutants)
            .HasForeignKey(m => m.OriginalCodeId)
            .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);

        modelBuilder.Entity<Mutant>()
            .HasOne(m => m.DifficultyLevel)
            .WithMany(dl => dl.Mutants)
            .HasForeignKey(m => m.DifficultyLevelId)
            .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);

Теперь, когда я запрашиваю Мутанты, OriginalCode имеет значение null:

Null OriginalCode

но как только я запрашиваю OriginalCode как показано ниже:

OriginalCodes

тогда поле OriginalCode мутантов будет не нулевым:

Filled Object

В чем причина и как я могу это исправить?

Ответ 1

Причина объясняется в разделе " Загрузка связанных данных " документации EF Core.

Первое поведение заключается в том, что EF Core в настоящее время не поддерживает ленивую загрузку, поэтому обычно вы получите null для свойств навигации, пока вы не загрузите их с помощью нетерминальной или явной загрузки. Однако раздел загрузки Eager содержит следующее:

Совет
Entity Framework Core автоматически исправляет свойства навигации для любых других объектов, которые ранее были загружены в экземпляр контекста. Поэтому, даже если вы явно не включаете данные для свойства навигации, свойство все равно может быть заполнено, если ранее были загружены некоторые или все связанные объекты.

что объясняет, почему свойство навигации не является нулевым во втором случае.

Теперь я не уверен, какое из двух типов поведения вы хотите исправить, поэтому попытайтесь решить оба вопроса.

Первое поведение может быть "исправлено" с использованием одного из доступных в настоящее время методов для загрузки связанных данных, например, с нетерпением загрузки:

var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();

Второе поведение "по дизайну" и не может контролироваться. Если вы хотите избежать этого, обязательно используйте новый экземпляр DbContext только для выполнения одного запроса, чтобы повторить необходимые данные.

Обновление: начиная с версии 2.1, EF Core поддерживает Lazy Loading. Однако он не включен по умолчанию, поэтому для его использования нужно пометить все свойства навигации virtual, установить Microsoft.EntityFrameworkCore.Proxies и включить его с помощью вызова UseLazyLoadingProxies или использовать Lazy-загрузку без прокси-серверов - как объяснено примерами в EF Core документация.