query lazyloadingenabled lazy framework async and c# entity-framework entity-framework-6

c# - lazyloadingenabled - EF Eager recuperando clase derivada



lazy and eager loading in entity framework (2)

En breve, no es posible de la caja.

La única solución alternativa que puedo sugerir es materializar el resultado de la consulta maestra, luego ejecutar varias consultas de tipo OfType con las OfType necesarias utilizando el mismo filtro que la consulta maestra y confiar en la corrección de la propiedad de navegación de EF.

Requiere una propiedad de navegación inversa en la clase Base :

public abstract class Base { // ... public A A { get; set; } }

Entonces puedes usar algo como esto:

public IEnumerable<A> GetAll(string id) { var a = _ctx.A.Where(x => x.Id == id).ToList(); _ctx.Base.OfType<Base1>().Include(e => e.SomeClass).Where(e => e.A.Id == id).Load(); _ctx.Base.OfType<Base3>().Include(e => e.SomeOtherClass).Where(e => e.A.Id == id).Load(); return a; }

La misma idea se puede usar sin propiedad de navegación inversa pero con el uso de los Id de base devueltos como filtro:

public IEnumerable<A> GetAll(string id) { var a = _ctx.A.Include(e => e.Bases) .Where(x => x.Id == id).ToList(); var baseIds = a.SelectMany(e => e.Bases.OfType<ModelA.Base1>().Select(b => b.Id)); db.Base.OfType<Base1>().Include(e => e.SomeClass) .Where(e => baseIds.Contains(e.Id)).Load(); baseIds = a.SelectMany(e => e.Bases.OfType<Base3>().Select(b => b.Id)); db.Base.OfType<Base3>().Include(e => e.SomeOtherClass) .Where(e => baseIds.Contains(e.Id)).Load(); return a; }

Estoy usando EF6 y estoy tratando de buscar ansiosamente toda la estructura de un objeto. El problema es que estoy usando herencia.

Digamos que tengo estas clases.

DbContext

DbSet<A> A { get; set; }

Clases de ejemplo

public class A { public string Id { get; set; } public IList<Base> Bases { get; set; } } public abstract class Base { public int Id { get; set; } public string Name { get; set; } } public abstract class Base1 : Base { public SomeClass SomeClass { get; set; } } public class Base2 : Base1 { } public class Base3 : Base1 { public SomeOtherClass SomeOtherClass { get; set; } }

El error que recibo es:

The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.

¿Por qué no funciona con lo siguiente?

public IEnumerable<A> GetAll(string id) { return _ctx.A .Include(x => x.Bases.OfType<Base1>().Select(y=>y.SomeClass)) .Where(x => x.Id.Equals(id)).ToList(); }

Nuevo ejemplo

public IEnumerable<A> GetAll(string id) { var lists = _dbContext.A.Where(x => x.Id == id); lists.SelectMany(a => a.Bases).OfType<Base1>().Include(e=>e.SomeClass).Load(); lists.SelectMany(b => b.Bases).OfType<Base3>().Include(e => e.SomeOtherClass).Load(); return lists; }

EDITAR: Agregó un nuevo ejemplo que parece funcionar.


Su problema no está en el Select(y=>y.SomeClass) sí mismo, si intenta eliminarlo de su consulta y ejecutar su consulta nuevamente, obtendrá el mismo problema. No puede consultar el tipo heredado como hijo y espera que desde el marco de la entidad se ocupe de todo.

Si observa su base de datos, la tabla Base tiene una referencia a A que es la relación 1, muchas de A a Base.

puede obtener todas las entidades Base donde A.Id = something , agregando una propiedad de navegación A en la clase Base , y en su DbContext agrega DbSet<Base> Bases{get;set;} entonces su consulta se verá así

var details = _ctx.Bases.OfType<Base1>() .Include(t=>t.Box) .Include(t=>t.SomeClass) .Where(t=>t.Box.Id ==something);

Otra opción, para usar un DTO, en el ejemplo siguiente utilicé el tipo Anonymous , pero puede crear un DTO fuertemente tipado para cumplir con sus requisitos.

var details = _ctx.A .Where (t=>t.Id ==something) .Select(a => new { Id = a.Id, // ... other A properites , Bases = _ctx.Bases.OfType<Base1>().Select(m=> new { Id = m.Id, Name = m.Name, SomeClass = m.SomeClass }); }

Espero que esto te ayudará