Ho un metodo fuori dal mio contesto db che assomiglia a questo:
public override async Task<IEnumerable<FeedMessage>> GetLatestFeeds(
int userId,
int groupId,
int maxResults = 15,
long lastId = 0)
{
if (lastId == 0) lastId = long.MaxValue;
var userSpecific =
FeedMessages.Where(fm =>
fm.UserId.HasValue && fm.UserId.Value == userId && fm.Id < lastId && !fm.IsDeleted);
var groupSpecific =
FeedMessages.Where(fm =>
fm.UserId == null && fm.GroupId.HasValue && fm.GroupId.Value == groupId && fm.Id < lastId && !fm.IsDeleted);
var siteWide =
FeedMessages.Where(fm =>
fm.UserId == null && fm.GroupId == null && fm.Id < lastId && !fm.IsDeleted);
var feeds = await
userSpecific.Union(groupSpecific).Union(siteWide)
.OrderByDescending(x => x.Id)
.Take(maxResults)
.ToListAsync();
return feeds.OrderBy(x => x.Id);
}
l'idea qui è che voglio prendere i record che sono specifici per utente, specifici per gruppo o generici, organizzarli per ID e restituire i primi risultati X.
Se eseguo questo ottengo un'intera schermata di errori:
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'Union({from FeedMessage fm in value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[MySolution.Common.Entities.FeedMessage]) where ((((([fm].UserId == null) AndAlso ([fm].GroupId != null)) AndAlso (Convert([fm].GroupId, Int32) == __groupId_2)) AndAlso ([fm].Id < __lastId_3)) AndAlso Not([fm].IsDeleted)) select [fm]})' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'Union({from FeedMessage fm in value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[MySolution.Common.Entities.FeedMessage]) where (((([fm].UserId == null) AndAlso ([fm].GroupId == null)) AndAlso ([fm].Id < __lastId_4)) AndAlso Not([fm].IsDeleted)) select [fm]})' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'Union({from FeedMessage fm in value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[MySolution.Common.Entities.FeedMessage]) where ((((([fm].UserId == null) AndAlso ([fm].GroupId != null)) AndAlso (Convert([fm].GroupId, Int32) == __groupId_2)) AndAlso ([fm].Id < __lastId_3)) AndAlso Not([fm].IsDeleted)) select [fm]})' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'Union({from FeedMessage fm in value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[MySolution.Common.Entities.FeedMessage]) where (((([fm].UserId == null) AndAlso ([fm].GroupId == null)) AndAlso ([fm].Id < __lastId_4)) AndAlso Not([fm].IsDeleted)) select [fm]})' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'orderby [x].Id desc' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'Take(__p_5)' could not be translated and will be evaluated locally.
Che cosa sta succedendo qui? E come lo aggiusto? Questo sarà un grande tavolo, la valutazione locale schiaccerà il sistema.
Ho finito per fare un bug report sul sito github di EF Core, e diverse ore dopo ho ottenuto una risposta che potevo usare. Risulta che Union()
, Concat()
, Except()
e Intersect()
non sono ancora supportati per le operazioni sul lato server. :\
Questo non è stato immediatamente evidente nelle mie ricerche sul web.
Per consiglio del team di sviluppo, sono stato in grado di riscrivere la mia domanda in questo modo:
return FeedMessages
.Where(fm => fm.Id < lastId && !fm.IsDeleted && (
(fm.UserId.HasValue && fm.UserId.Value == userId) ||
(fm.UserId == null && fm.GroupId.HasValue && fm.GroupId.Value == groupId) ||
(fm.UserId == null && fm.GroupId == null)))
.OrderByDescending(x => x.Id)
.Take(maxResults)
.OrderBy(x => x.Id)
.ToListAsync();
... che mi ha portato fuori dalla modalità di crisi, ma mi piacerebbe semplicemente lanciarci lì a tutti gli sviluppatori di EF Core che guardano questi post che questa è una funzionalità importante e (IMO) dovrebbe essere data la priorità non appena realisticamente possibile.