Precedentemente (quando si utilizza .net 4.5.2 e EF 6). Ho avuto un metodo Get
generico che ha accettato un numero di include come segue;
public abstract class DataContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>, IDataContext
{
public DataContext(DbContextOptions options)
: base(options)
{
}
// reduced for brevity
public T Get<T>(int id, params Expression<Func<T, object>>[] includes) where T : class, IEntity
{
return this.Set<T>().Include(includes).FirstOrDefault(x => x.Id == id);
}
Vorrei quindi chiamare per esempio;
context.Get<Job>(id,
x => x.Equipment,
x => x.Equipment.Select(y => y.Type));
Per includere Job.Equipment
e anche Job.Equipment.Type
.
Tuttavia, quando ho portato questo su asp.net core 2. Ho provato lo stesso approccio generico, ma se provo ad includere una sub-entità ottengo il seguente errore;
L'espressione di proprietà 'x => {da Equipment y in x.Equipment select [y] .Type}' non è valida. L'espressione dovrebbe rappresentare un accesso alla proprietà: 't => t.MyProperty'. Per ulteriori informazioni sull'inclusione dei dati correlati, vedere http://go.microsoft.com/fwlink/?LinkID=746393 .
Qualcuno può suggerire come posso aggirare questo per includere le sub entità nel mio metodo Get<T>
Generico con Entity Framework Core 2?
Aggiornare
Dal guardare i documenti c'è un ulteriore metodo di inclusione
include(string navigationPropertyPath)
Ho aggiunto il seguente metodo;
public T Get<T>(int id, string[] includes) where T : class, IEntity
{
var result = this.Set<T>().AsQueryable();
foreach(var include in includes)
{
result = result.Include(include);
}
return result.FirstOrDefault(x => x.Id == id);
}
Che funziona, anche se non sono convinto dell'efficienza qui?
ThenInclude
pattern EF Core Include
/ ThenInclude
non può essere rappresentato da Expression<Func<T, object>>[]
come in EF6.
Guardando il codice sorgente di una delle estensioni EF Core - Microsoft.EntityFrameworkCore.UnitOfWork , che afferma di essere
Un plugin per Microsoft.EntityFrameworkCore per supportare repository, unità di modelli di lavoro e più database con transazioni distribuite supportate.
sembra che il modello previsto per include dovrebbe essere basato su Func<IQueryable<T>, IIncludableQueryable<T, object>>
:
public T Get<T>(int id, Func<IQueryable<T>, IIncludableQueryable<T, object>> include = null) where T : class, IEntity
{
var result = this.Set<T>().AsQueryable();
if (include != null)
result = include(result);
return result.FirstOrDefault(x => x.Id == id);
}
Lo svantaggio è che aggiunge dipendenza EF Core al chiamante e richiede l' using Microsoft.EntityFrameworkCore;
. Che nel tuo caso non è essenziale dato che stai estendendo DbContext
.
L'utilizzo con il tuo esempio potrebbe essere:
context.Get<Job>(id, q => q
.Include(x => x.Equipment)
.ThenInclude(y => y.Type));
Puoi fare qualcosa del genere:
public abstract class DataContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>, IDataContext
{
public DataContext(DbContextOptions options)
: base(options)
{
}
// reduced for brevity
public T Get<T>(int id, Func<IQueryable<T>, IIncludableQueryable<T, object>> includes = null) where T : class, IEntity
{
IQueryable<T> queryable = this.Set<T>();
if (includes != null)
{
queryable = includes(queryable);
}
return queryable.FirstOrDefault(x => x.Id == id);
}
}
context.Get<Job>(id, includes: source => source.Include(x => x.Equipment).ThenInclude(x => x.Type));