Sto riscontrando un problema con l'ottenimento di un risultato quando si tenta di ottenere oggetti con più livelli. Questo è quello che sto cercando di fare grosso modo:
_context.Investors.Where(s => s.Id == userId)
.Include(c => c.Coins) //only want this if some kind of flag is given by the user.
.ThenInclude(ct => ct.CoinType)
.Include(c => c.Bricks) //only want this if some kind of flag is given by the user.
In sostanza sto ricevendo molte bandiere che indicano se dovrei includere parti dell'oggetto. Ho quasi finito di lavorare. Come questo:
_context.Investors.Where(s => s.Id == userId)
.Select(i => new
{
i,
Bricks = (details & GapiInvestorFlags.Bricks) != GapiInvestorFlags.Bricks ? null : i.Bricks,
Offers = (details & GapiInvestorFlags.Offers) != GapiInvestorFlags.Offers ? null : i.Offers,
Coins = (details & GapiInvestorFlags.Coins) != GapiInvestorFlags.Coins ? null : i.Coins,
CoinTransactions = (details & GapiInvestorFlags.CoinTransactions) != GapiInvestorFlags.CoinTransactions ? null : i.CoinTransactions,
OfferTransactions = (details & GapiInvestorFlags.OfferTransactions) != GapiInvestorFlags.OfferTransactions ? null : i.OfferTransactions,
BuyTransactions = (details & GapiInvestorFlags.BuyTransactions) != GapiInvestorFlags.BuyTransactions ? null : i.BuyTransactions,
SellTransactions = (details & GapiInvestorFlags.SellTransactions) != GapiInvestorFlags.SellTransactions ? null : i.SellTransactions
}).AsEnumerable()
.Select(e => e.i).FirstOrDefault();
Questo funziona eccetto il fatto che la sezione Monete contiene anche una moneta e quindi devo includerla anch'io. Ma quando aggiungo il mio codice, l'intera sezione smette di funzionare.
Questo è quello che ho provato:
_context.Investors.Where(s => s.Id == userId)
.Include(c => c.Coins)
.ThenInclude(ct => ct.CoinType)
.Select(i => new
{
i,
Bricks = (details & GapiInvestorFlags.Bricks) != GapiInvestorFlags.Bricks ? null : i.Bricks,
Offers = (details & GapiInvestorFlags.Offers) != GapiInvestorFlags.Offers ? null : i.Offers,
Coins = (details & GapiInvestorFlags.Coins) != GapiInvestorFlags.Coins ? null : i.Coins.Select(c => new { c, c.CoinType }).ToList(),
CoinTransactions = (details & GapiInvestorFlags.CoinTransactions) != GapiInvestorFlags.CoinTransactions ? null : i.CoinTransactions,
OfferTransactions = (details & GapiInvestorFlags.OfferTransactions) != GapiInvestorFlags.OfferTransactions ? null : i.OfferTransactions,
BuyTransactions = (details & GapiInvestorFlags.BuyTransactions) != GapiInvestorFlags.BuyTransactions ? null : i.BuyTransactions,
SellTransactions = (details & GapiInvestorFlags.SellTransactions) != GapiInvestorFlags.SellTransactions ? null : i.SellTransactions
}).AsEnumerable()
.Select(e => e.i).FirstOrDefault();
Non riesco davvero a capire perché non funzioni.
Fondamentalmente quando cambio:
i.Coins
A
i.Coins.Select(c => new { c, c.CoinType }).ToList()
smette di funzionare.
La tecnica che stai utilizzando non è un caricamento esplicito ( Include
/ ThenInclude
), ma un trucco basato sulla proiezione e la correzione della proprietà di navigazione di EF Core, quindi non posso dire perché smette di funzionare. EF Core elabora ancora le proiezioni e include in modo diverso, quindi potrebbe essere un difetto nell'elaborazione corrente.
L'implementazione di include condizionale a livello di query radice è relativamente semplice. Si noti che il metodo Include
inizia da (è definito per) IQueryable<TEntity>
e il risultato restituibile IIncludableQueryable<TEntity, TPreviousProperty>>
è anche IQueryable<TEntity>
. Ciò significa che puoi mantenere IQueryable<T>
variabile di query e applicare trasformazioni condizionali simili agli operatori Where
concatenati.
Per semplificare, puoi creare un metodo di estensione helper personalizzato come questo:
public static IQueryable<T> If<T>(
this IQueryable<T> source,
bool condition,
Func<IQueryable<T>, IQueryable<T>> transform
)
{
return condition? transform(source) : source;
}
e usalo in questo modo:
_context.Investors.Where(s => s.Id == userId)
.If(flagCoins, q => q.Include(e => e.Coins)
.ThenInclude(e => e.CoinType))
.If(flagBricks, q => q.Include(e => e.Bricks))
Se hai bisogno di qualcosa di simile per i livelli nidificati ( ThenInclude
), quindi aggiungi i seguenti 2 metodi di estensione:
public static IQueryable<T> If<T, P>(
this IIncludableQueryable<T, P> source,
bool condition,
Func<IIncludableQueryable<T, P>, IQueryable<T>> transform
)
where T : class
{
return condition ? transform(source) : source;
}
public static IQueryable<T> If<T, P>(
this IIncludableQueryable<T, IEnumerable<P>> source,
bool condition,
Func<IIncludableQueryable<T, IEnumerable<P>>, IQueryable<T>> transform
)
where T : class
{
return condition ? transform(source) : source;
}
che ti permetterà di usare qualcosa come questo:
_context.Investors.Where(s => s.Id == userId)
.If(flagCoins, q => q.Include(e => e.Coins)
.If(flagCoinType, q2 => q2.ThenInclude(e => e.CoinType)))
.If(flagBricks, q => q.Include(e => e.Bricks))