EF Core: Distinct and OrderBy strange behavior - c#

I migrate my old project to the new EF Core and found this problem
My old code:
private IQueryable<SeriesData> GetSeriesData(IQueryable<Series> query, long? userId = null)
{
DateTime date = DateTime.Today.AddMonths(1);
IQueryable<SeriesData> seriesDataQuery = query.Select(x => new SeriesData
{
Series = x,
Subscribed = userId.HasValue && x.Subscriptions.Any(y => y.UserId == userId),
CurrentSeasonNumber = x.Episodes.Where(z => z.ReleaseDate.HasValue && z.ReleaseDate < date).Max(y => y.SeasonNumber),
Channel = x.Channel,
Country = x.Channel.Country,
ReleaseGroups =
x.Episodes.SelectMany(z => z.Releases)
.Select(y => y.ReleaseGroup)
.Distinct() // 1
.OrderBy(y => y.Name) // 2
.Select(r => new ReleaseGroupData
{
ReleaseGroup = r,
Subscribed =
userId.HasValue &&
x.Subscriptions.Any(y => y.UserId == userId && y.ReleaseGroupId == r.Id)
}).ToList()
});
return seriesDataQuery;
}
When i execute this query i get "InvalidOperationException: Sequence contains more than one element" exception
But if i swap line 1 and 2 everything works.

Related

Linq Group by with nested collection throwing Cannot perform an aggregate function

I want to do something like this:
var projectHistory = await Context.Tasks.GroupBy(x => x.ProjectId).Select(x => new ProjectHistoryStatModel
{
ProjectId = x.Key,
CompletedTasks = x.Where(y => y.StatusId == 4).Count(),
InProgressTasks = x.Where(y => y.StatusId == 3).Count(),
DelayedTasks = x.Where(y => y.EndDate < DateTime.Now && y.StatusId != 4).Count(),
DependentTasks = x.Where(y => y.Dependents.Any()).Count(),
TotalTasks = x.Count()
}).ToListAsync();
But DependentTasks property DependentTasks = x.Where(y => y.Dependents.Any()).Count(), is throwing:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Well y.Dependents is a Collection that is why its throwing the problem, I also tried this: DependetTasks = Context.TaskDependencies.Where(y => x.Any(z => z.Id == y.TaskId)).Count(), and it throws the same error.
Can you guys show me a way of doing this in the same request to the DB?
Regards
Assuming that you are using EF Core < 6.0, you can try to rewrite your query in the following way:
var query =
from t in Context.Tasks
group new { t, HasDependents = t.Dependents.Any() } by t.ProjectId into g
select new ProjectHistoryStatModel
{
ProjectId = g.Key,
CompletedTasks = g.Where(y => y.t.StatusId == 4).Count(),
InProgressTasks = g.Where(y => y.t.StatusId == 3).Count(),
DelayedTasks = g.Where(y => y.t.EndDate < DateTime.Now && y.t.StatusId != 4).Count(),
DependentTasks = g.Where(y => y.HasDependents).Count(),
TotalTasks = g.Count()
};
var projectHistory = await query.ToListAsync();
EF Core up to 6.0 do not support translating navigation properties after GroupBy.

LINQ Query Multiple Group and count of latest record - Oracle DB

I tried to divided Linq queries into 3 (total, success, fail) but so far "Total" Linq query is working fine. Please help me to get "Success", "Fail" columns (it has mulitple statuses and we have to check the last column of each transaction and destination)
Note: you need to group by ProcessTime, TransactionId, Destination and check last column whether it is success or Fail then apply count (we are using oracle as backend)
LINQ for Total count
var query = (from filetrans in context.FILE_TRANSACTION
join route in context.FILE_ROUTE on filetrans.FILE_TRANID equals route.FILE_TRANID
where
filetrans.PROCESS_STRT_TIME >= fromDateFilter && filetrans.PROCESS_STRT_TIME <= toDateFilter
select new { PROCESS_STRT_TIME = DbFunctions.TruncateTime((DateTime)filetrans.PROCESS_STRT_TIME), filetrans.FILE_TRANID, route.DESTINATION }).
GroupBy(p => new { p.PROCESS_STRT_TIME, p.FILE_TRANID, p.DESTINATION });
var result = query.GroupBy(x => x.Key.PROCESS_STRT_TIME).Select(x => new { x.Key, Count = x.Count() }).ToDictionary(a => a.Key, a => a.Count);
Check this solution. If it gives wrong result, then I need more details.
var fileTransQuery =
from filetrans in context.AFRS_FILE_TRANSACTION
where accountIds.Contains(filetrans.ACNT_ID) &&
filetrans.PROCESS_STRT_TIME >= fromDateFilter && filetrans.PROCESS_STRT_TIME <= toDateFilter
select filetrans;
var routesQuery =
from filetrans in fileTransQuery
join route in context.AFRS_FILE_ROUTE on filetrans.FILE_TRANID equals route.FILE_TRANID
select route;
var lastRouteQuery =
from d in routesQuery.GroupBy(route => new { route.FILE_TRANID, route.DESTINATION })
.Select(g => new
{
g.Key.FILE_TRANID,
g.Key.DESTINATION,
ROUTE_ID = g.Max(x => x.ROUTE_ID)
})
from route in routesQuery
.Where(route => d.FILE_TRANID == route.FILE_TRANID && d.DESTINATION == route.DESTINATION && d.ROUTE_ID == route.ROUTE_ID)
select route;
var recordsQuery =
from filetrans in fileTransQuery
join route in lastRouteQuery on filetrans.FILE_TRANID equals route.FILE_TRANID
select new { filetrans.PROCESS_STRT_TIME, route.CRNT_ROUTE_FILE_STATUS_ID };
var result = recordsQuery
.GroupBy(p => DbFunctions.TruncateTime((DateTime)p.PROCESS_STRT_TIME))
.Select(g => new TrendData
{
TotalCount = g.Sum(x => x.CRNT_ROUTE_FILE_STATUS_ID != 7 && x.CRNT_ROUTE_FILE_STATUS_ID != 8 ? 1 : 0)
SucccessCount = g.Sum(x => x.CRNT_ROUTE_FILE_STATUS_ID == 7 ? 1 : 0),
FailCount = g.Sum(x => failureStatus.Contains(x.CRNT_ROUTE_FILE_STATUS_ID) ? 1 : 0),
Date = g.Min(x => x.PROCESS_STRT_TIME)
})
.OrderBy(x => x.Date)
.ToList();

System.InvalidOperationException issue in LINQ expression

When I run the following Linq:
var selectedProduct = db.Products.FirstOrDefault(a => a.ProductNr == productNr)?.Id;
model.PackTypes = db.Zones
.Where(az => az.ProductId == selectedProduct && az.StoragePrio > 0)
.ToList()
.DistinctBy(p => p.PackType)
.OrderBy(x => x.PackType)
.Select(x => new DropdownItemViewModel<int>
{
Id = (int)x.PackType,
Name = x.PackType.Translate()
});
return true;
I get this error:
System.InvalidOperationException: 'Nullable object must have a value.' on this code Id = (int)x.PackType,
Now I know I must do a nullcheck so I have tried this:
if (x.PackType != null)
return new DropdownItemViewModel<int>
{
Id = (int)x.PackType,
Name = x.PackType.Translate()
};
return null;
Still doesn't work, by that I mean I still have problem with NullCheck.
This query more effective and should not have all mentioned errors:
var query =
from p in db.Products
where p.ProductNr == productNr
join az in db.Zones on p.Id equals az.ProductId
where az.StoragePrio > 0 && az.PackType != null
select new { az.PackType };
model.PackTypes = query
.Distinct()
.OrderBy(x => x.PackType)
.Select(x => new DropdownItemViewModel<int>
{
Id = (int)x.PackType,
Name = x.PackType.Translate()
})
.ToList();
Instead of two database requests this query sends only one. Also all operations are done on the server side.

Two dbcontexts cause an error "value cannot be null. parameter name entitytype"

I have 2 DbContexts in my application, and need to do a join in 2 tables that are each one in a different DbContext; I get this error
value cannot be null. parameter name entitytype
When I try to join 2 tables of the same context, this error does not happen.
var VerificaExistenciaSinistro = sinistroContext.SnsAviso
.Join(
sinistroContext.SnsNumAviso,
sinistro => sinistro.NumApo,
aviso => aviso.NumApo,
(sinistro, aviso) => new {
sinistroV = sinistro,
avisoV = aviso })
.Where(c => c.sinistroV.CodItm == c.avisoV.CodItm &&
c.sinistroV.NumApo == c.avisoV.NumApo &&
c.sinistroV.NumAvs == c.avisoV.SeqNumAvs)
.Join(sgsContext.EmsEmissao,
sinistro1 => sinistro1.sinistroV.CodCtrtAvs,
emissao => emissao.CodCtrt,
(sinistro1, emissao) => new {
sinistroC = sinistro1,
emissaoC = emissao })
.Where(c => c.sinistroC.sinistroV.CodCtrtAvs == c.emissaoC.CodCtrt &&
c.emissaoC.CodEmis == c.sinistroC.avisoV.CodEms)
.Where(x => x.sinistroC.sinistroV.NumApo == apolice &&
x.emissaoC.StsEmis == emissao &&
x.emissaoC.NumEndosso ==endosso &&
x.sinistroC.sinistroV.CodItm == cod_itm &&
x.sinistroC.sinistroV.CodCbe == cbeCod)
.Select(x => x.sinistroC)
.ToList();
It generally occurs when u query data from two dbcontext using IQueryable
I encountered the same issue when I was using two dbContext. The solution which I found was. If u are using join between two tables then load any one table's data first to a variable/Object so that It becomes IEnumerable or IList and then do join with that variable/Object to the another table of another dbContext
Example
var FirstDbContextTable = sinistroContext.SnsAviso
.Join(
sinistroContext.SnsNumAviso,
sinistro => sinistro.NumApo,
aviso => aviso.NumApo,
(sinistro, aviso) => new {
sinistroV = sinistro,
avisoV = aviso })
.Where(c => c.sinistroV.CodItm == c.avisoV.CodItm &&
c.sinistroV.NumApo == c.avisoV.NumApo &&
c.sinistroV.NumAvs == c.avisoV.SeqNumAvs).ToList();
var result=FirstDbContextTable.Join(sgsContext.EmsEmissao,
sinistro1 => sinistro1.sinistroV.CodCtrtAvs,
emissao => emissao.CodCtrt,
(sinistro1, emissao) => new {
sinistroC = sinistro1,
emissaoC = emissao })
.Where(c => c.sinistroC.sinistroV.CodCtrtAvs == c.emissaoC.CodCtrt &&
c.emissaoC.CodEmis == c.sinistroC.avisoV.CodEms)
.Where(x => x.sinistroC.sinistroV.NumApo == apolice &&
x.emissaoC.StsEmis == emissao &&
x.emissaoC.NumEndosso ==endosso &&
x.sinistroC.sinistroV.CodItm == cod_itm &&
x.sinistroC.sinistroV.CodCbe == cbeCod)
.Select(x => x.sinistroC)
.ToList();

I'm getting an error when trying to join against multiple tables in a query

I getting this error when I join:
An exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: The specified LINQ expression contains references to queries that are associated with different contexts.
var rightsList = RoleRightService.GetRoleRights<RoleRight>().Where(x => x.RoleCode == role && x.CompanyId == USER_OBJECT.CompanyId).AsEnumerable();
var securables = SecurableServices.GetSecurable<Securable>()
.GroupBy(a => new { a.RegistrationType_LookUpId })
.Select(r => new
{
id = r.Select(x => x.SecurableID),
registrationType = r.Key.RegistrationType_LookUpId,
RegistrationTypeName = r.Select(x => x.RegistrationType.LookUpDescription).Distinct().FirstOrDefault(),
IsChecked = false,
pageList = r.GroupBy(b => new { b.PageID })
.Select(p => new SecurableViewModel
{
Id = p.Where(x => x.PageID == p.Key.PageID && x.Type == 1).Select(x => x.SecurableID).FirstOrDefault(),
PageId = p.Where(x => x.PageID == p.Key.PageID && x.Type == 1).Select(x => x.PageID).FirstOrDefault(),
PageName = p.Where(x => x.PageID == p.Key.PageID && x.Type == 1).Select(x => x.PageDescription).FirstOrDefault(),// && rr.AccessRight !=0
IsChecked = rightsList.Where(rr => rr.SecurableID == (p.Where(x => x.PageID == p.Key.PageID && x.Type == 1).Select(x => x.SecurableID).FirstOrDefault())).Count() > 0,
operationList = r.Where(x => x.PageID == p.Key.PageID && x.Type == 2)
.Select(o => new RoleRightViewModel
{
Id = o.SecurableID,
OperationID = o.OperationID,
OperationName = o.OperationDescription,
IsChecked = rightsList.Where(rr => rr.SecurableID == o.SecurableID).Count() > 0,
})
.ToList()
}).ToList()
}).ToList();
I am getting error
The specified LINQ expression contains references to queries that are associated with different contexts.
For this line:
IsChecked = rightsList.Where(rr => rr.SecurableID == (p.Where(x => x.PageID == p.Key.PageID && x.Type == 1).Select(x => x.SecurableID).FirstOrDefault())).Count() > 0,
is there possibilty to right delegate for this
It looks like you are using multiple EF entity contexts, possibly to query more than one database. EF is not able to perform a linq to entities query across more than one EF context.
In order to execute this query without error is will be necessary to use linq to objects instead by projecting the data from each context into memory before combining them. Please note this may have a negative performance impact since all objects will need to be fetched into memory before being filtered down.
Try adding a .ToList() between your GroupBy and Select statements:
var securables = SecurableServices.GetSecurable<Securable>()
.GroupBy(a => new { a.RegistrationType_LookUpId })
.ToList()
.Select(r => new
...

Categories