EF Core devuelve relaciones nulas hasta el acceso directo
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 OnModelCreating
de DBContext
hice 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:
pero tan pronto como solicite OriginalCode
s como a continuación:
entonces el OriginalCode
campo de los mutantes no será nulo:
¿Cuál es el motivo y cómo podría solucionarlo?
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á null
propiedades 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 DbContext
instancia 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 UseLazyLoadingProxies
una llamada, o utilizar la carga diferida sin servidores proxy ; ambos se explican con ejemplos en la documentación de EF Core.
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);
}
}
}
}