EF Core devuelve relaciones nulas hasta el acceso directo

Resuelto ConductedClever asked hace 7 años • 2 respuestas

Tengo algunos modelos como los siguientes:

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; }
}

y

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

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

y en el OnModelCreatingde DBContexthice las relaciones como estas:

        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);

Ahora, cuando solicito Mutantes, el Código Original es nulo:

Código original nulo

pero tan pronto como solicite OriginalCodes como a continuación:

Códigos originales

entonces el OriginalCodecampo de los mutantes no será nulo:

Objeto relleno

¿Cuál es el motivo y cómo podría solucionarlo?

ConductedClever avatar Feb 19 '17 20:02 ConductedClever
Aceptado

El motivo se explica en la sección Carga de datos relacionados de la documentación de EF Core.

El primer comportamiento se debe a que EF Core actualmente no admite la carga diferida, por lo que normalmente obtendrá nullpropiedades de navegación hasta que las cargue específicamente mediante carga inmediata o explícita. Sin embargo, la sección Carga ansiosa contiene lo siguiente:

Consejo
Entity Framework Core corregirá automáticamente las propiedades de navegación de cualquier otra entidad que se haya cargado previamente en la instancia de contexto. Por lo tanto, incluso si no incluye explícitamente los datos de una propiedad de navegación, la propiedad aún puede completarse si algunas o todas las entidades relacionadas se cargaron previamente.

lo que explica por qué la propiedad de navegación no es nula en el segundo caso.

Ahora, no estoy seguro de cuál de los dos comportamientos desea corregir, así que intentaré abordar ambos.

El primer comportamiento se puede "arreglar" utilizando uno de los métodos disponibles actualmente para cargar datos relacionados, por ejemplo, carga ansiosa:

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

El segundo comportamiento es "por diseño" y no se puede controlar. Si desea evitarlo, asegúrese de utilizar una DbContextinstancia nueva y nueva solo para ejecutar una única consulta para recuperar los datos necesarios, o no utilice ninguna consulta de seguimiento .

Actualización: a partir de v2.1, EF Core admite carga diferida . Sin embargo, no está habilitado de forma predeterminada, por lo que para utilizarlo se deben marcar todas las propiedades de navegación virtual, instalar Microsoft.EntityFrameworkCore.Proxies y habilitarlo mediante UseLazyLoadingProxiesuna llamada, o utilizar la carga diferida sin servidores proxy ; ambos se explican con ejemplos en la documentación de EF Core.

Ivan Stoev avatar Feb 19 '2017 15:02 Ivan Stoev

Usando la consola del Administrador de paquetes instale Microsoft.EntityFrameworkCore.Proxies

install-package Microsoft.EntityFrameworkCore.Proxies

Y luego en tu clase de Contexto agrega .UseLazyLoadingProxies():

namespace SomeAPI.EFModels
{
    public partial class SomeContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder
                    .UseLazyLoadingProxies()
                    .UseSqlServer(connectionString);
            }

        }
    }
}
joym8 avatar Oct 15 '2021 21:10 joym8