This question already has an answer here:
How to select top N rows for each group in a Entity Framework GroupBy with EF 3.1
(1 answer)
Closed 6 months ago.
This is my first time using an anonymous function with LINQ syntax. We are getting multiple Id's to set up a way for us to query another table for a specific "effective date" but something is throwing off my query.
Error Message
'((Microsoft.AspNetCore.Http.DefaultHttpContext)httpContext).Session' threw an exception of type 'System.InvalidOperationException'
"System.InvalidOperationException: The LINQ expression
'GroupByShaperExpression:\nKeySelector: new { \n operatorId =
t.OperatorId, \n regionId = t.RegionId\n },
\nElementSelector:new { \n operatorId =
ProjectionBindingExpression: operatorId, \n regionId =
ProjectionBindingExpression: regionId, \n effectiveDate =
ProjectionBindingExpression: effectiveDate\n }\n
.OrderByDescending(ed => ed.effectiveDate)' could not be
translated. Either rewrite the query in a form that can be
translated, or switch to client evaluation explicitly by
inserting
a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or
'ToListAsync'.
Any help would be great!
Query
var opRegionEffectiveDate = await (from reg in _orppr.GetAllQueryable()
.Where(opReg => result.Select(o => o.Id).Contains(opReg.OperatorId)).Select(opReg => new {operatorId = opReg.OperatorId, regionId = opReg.RegionId, effectiveDate = opReg.EffectiveDate}).Distinct()
group reg by new {reg.operatorId, reg.regionId}
into regef
select new { oprId = regef.Key.operatorId, regId = regef.Key.regionId, efdate = regef.OrderByDescending(ed => ed.effectiveDate).FirstOrDefault()})
.ToListAsync();
Full Method
public async Task<IEnumerable<OperatorViewModel>> GetAllAsync()
{
var retList = new List<OperatorViewModel>();
var result = await _operatorRepository.GetAllQueryable().Include(o => o.GroupEmails).Where(o => o.TenantId == TenantId).ToListAsync();
// var regions = _orppr.GetAllQueryable();
var opRegionEffectiveDate = await (from reg in _orppr.GetAllQueryable()
.Where(opReg => result.Select(o => o.Id).Contains(opReg.OperatorId)).Select(opReg => new {operatorId = opReg.OperatorId, regionId = opReg.RegionId, effectiveDate = opReg.EffectiveDate}).Distinct()
group reg by new {reg.operatorId, reg.regionId}
into regef
select new { oprId = regef.Key.operatorId, regId = regef.Key.regionId, efdate = regef.OrderByDescending(ed => ed.effectiveDate).FirstOrDefault()})
.ToListAsync();
var regions = await _regionRepository.GetAllQueryable()
.Where(reg => opRegionEffectiveDate.Select(ore => ore.regId).Contains(reg.Id))
.ToListAsync();
foreach (var oper in result)
{
var regionsToAdd = opRegionEffectiveDate.Where(r => r.oprId == oper.Id).Select(r => r.regId);
var regionsList = regions.Where(r => regionsToAdd.Contains(r.Id));
// var currRegions = await regions.Where(opReg => opReg.OperatorId == oper.Id)
// .Include(opReg => opReg.Region)
// .Select(opReg => opReg.Region)
// .OrderBy(reg => reg.Name)
// .Distinct()
// .ToListAsync();
var currOper = _mapper.Map<Operator, OperatorViewModel>(oper);
currOper.Regions = _mapper.Map<IEnumerable<Region>, IEnumerable<RegionViewModel>>(regionsList);
foreach(var reg in currOper.Regions)
{
var item = opRegionEffectiveDate.Single(r => r.oprId == oper.Id && r.regId == reg.Id);
reg.EffectiveDate = item.efdate.ToString();
}
retList.Add(currOper);
}
return retList.OrderBy(r => r.OperatorName);
}
Try following :
var opRegionEffectiveDate = await (_orppr
.GetAllQueryable().Where(opReg => result.Select(o => o.Id).Contains(opReg.OperatorId))
.OrderByDescending(ed => ed.effectiveDate)
.Select(opReg => new {operatorId = opReg.OperatorId, regionId = opReg.RegionId, effectiveDate = opReg.EffectiveDate})
.GroupBy(reg =>new {reg.operatorId, reg.regionId})
.Select(x => x).FirstOrDefault()
.Select(x => new { oprId = x.Key.operatorId, regId = x.Key.regionId, x.effectiveDate})
.ToListAsync()
);
var opRegionEffectiveDate = await _orppr
.GetAllQueryable().Where(opReg => result.Select(o => o.Id).Contains(opReg.OperatorId))
.Distinct()
.OrderByDescending(ed => ed.effectiveDate)
.Select(opReg => new {operatorId = opReg.OperatorId, regionId = opReg.RegionId, effectiveDate = opReg.EffectiveDate})
.GroupBy(reg =>new {reg.operatorId, reg.regionId})
.Select(x => x).FirstOrDefault()
.Select(x => new { oprId = x.operatorId, regId = x.regionId, x.effectiveDate})
.ToListAsync();
Related
Good Morning,
I have a problem with the performance if i use include.
Have a look at the following query, if I load the data from the include (x.Server_Item.itemType) the query needs like 980ms.
If i remove them, the query needs 51ms.
980ms:
using (var db = new dbContext())
{
var items = db.Characters_Inventory
.Where(x => x.charId == charId && x.itemLocation == ItemLocationInventory)
.Include(p => p.Server_Items)
.AsSplitQuery()
.Select(x => new
{
itemId = x.id,
x.itemName,
x.nameTag,
x.itemAmount,
x.itemLocation,
x.isItemEquipped,
x.itemCategory,
x.metaId,
x.metaTag0,
x.metaTag1,
itemType = x.Server_Items.itemType,
itemSubType = x.Server_Items.itemSubType,
itemClothesType = x.Server_Items.Server_Clothes.type,
itemPicName = x.Server_Items.itemPicSRC,
itemWeight = x.Server_Items.itemWeight,
itemGender = x.Server_Items.Server_Clothes.gender,
isItemUseable = x.Server_Items.isItemUseable,
isItemDroppable = x.Server_Items.isItemDroppable,
isItemGiveable = x.Server_Items.isItemGiveable,
isItemStorable = x.Server_Items.isItemStorable,
isItemStackable = x.Server_Items.isItemStackable,
isItemShowable = x.Server_Items.isItemShowable,
isItemNameable = x.Server_Items.isItemNameable,
isItemPlaceable = x.Server_Items.isItemPlaceable,
//isClothesTypeEquipped = IsClothesTypeEquipped(charId, x.id),
isClothesSwitchable = x.Server_Items.Server_Clothes.altClothesName != "" ? true : false
//isWeaponTypeEquipped = IsWeaponTypeEquipped(charId, x.id),
//charName = Characters.GetCharacterName(x.metaId)
}).AsNoTracking().ToList();
return JsonConvert.SerializeObject(items);
}
50ms:
using (var db = new dbContext())
{
var items = db.Characters_Inventory
.Where(x => x.charId == charId && x.itemLocation == ItemLocationInventory)
.Include(p => p.Server_Items)
.AsSplitQuery()
.Select(x => new
{
itemId = x.id,
x.itemName,
x.nameTag,
x.itemAmount,
x.itemLocation,
x.isItemEquipped,
x.itemCategory,
x.metaId,
x.metaTag0,
x.metaTag1
}).AsNoTracking().ToList();
return JsonConvert.SerializeObject(items);
}
I tried with AsSplitQuery and without AsSplitQuery.
Maybe nice to know: On the included table (Server_Items) is alrdy a table included.
Thanks in advance.
Sincerely
I have an API LINQ list called examContents. Currently, it has been ordered by SectionId & DisplayOrder (no 1 & 2 as in the below picture). Now I want to add Tag Tile also as the third ordering option. Is there a way to do that in C# LINQ?
I tried adding .ThenBy(x=>x.Tags) & .ThenBy(x=>x.Tags.Title) next to DisplayOrder along with .OrderBy(t=>t.Type).ThenBy(t=>t.Title) next to Tags list. But it does not work. Can someone please help me on this?
var examContents = await this._context.ExamContents
.AsNoTracking()
.Where(x => x.IsNewVersion && versionIds.Contains(x.VersionId))
.Select(x => new ExamContentModel
{
Id = x.Id,
VersionId = x.VersionId,
LearningOutcomeId = x.LearningOutcomeId,
SectionId = x.SectionId,
Title = x.LearningOutcome.Title,
AssignedQuestionCount = x.AssignedQuestionCount,
DisplayOrder=x.DisplayOrder,
IsNewVersion=x.IsNewVersion,
Questions = x.LearningOutcome.Questions.Where(x => x.Category == QuestionCategory.Certification).Select(y => new Question
{
Title = y.Title,
Category = y.Category,
Status = y.Status,
IsDraft = y.IsDraft,
PublishedQuestionId = y.PublishedQuestionId,
ExamVersionId = y.ExamVersionId
}),
Tags = x.LearningOutcome.LearningOutcomeTags.Select(t => new Tag
{
Id = t.TagId,
Title = t.Tag.Title,
Type = t.Tag.Type,
IsRemovedFromLO = t.IsUntaggedFromLO
})
})
.OrderBy(x=>x.SectionId).ThenBy(x=>x.DisplayOrder)
.ToListAsync();
The error I am getting is:
The LINQ expression 'DbSet\r\n .Where(e => e.IsNewVersion && __versionIds_0\r\n .Contains(e.VersionId))\r\n .Join(\r\n outer: DbSet, \r\n inner: e => EF.Property<Nullable>(e, "LearningOutcomeId"), \r\n outerKeySelector: l => EF.Property<Nullable>(l, "Id"), \r\n innerKeySelector: (o, i) => new TransparentIdentifier<ExamContent, LearningOutcome>(\r\n Outer = o, \r\n Inner = i\r\n ))\r\n .OrderBy(e => e.Outer.SectionId)\r\n .ThenBy(e => e.Outer.DisplayOrder)\r\n .ThenBy(e => DbSet\r\n .Where(l0 => EF.Property<Nullable>(e.Inner, "Id") != null && EF.Property<Nullable>(e.Inner, "Id") == EF.Property<Nullable>(l0, "LearningOutcomeId"))\r\n .Join(\r\n outer: DbSet, \r\n inner: l0 => EF.Property<Nullable>(l0, "TagId"), \r\n outerKeySelector: t => EF.Property<Nullable>(t, "Id"), \r\n innerKeySelector: (o, i) => new TransparentIdentifier<LearningOutcomeTag, Tag>(\r\n Outer = o, \r\n Inner = i\r\n ))\r\n .OrderBy(l0 => l0.Inner.Type)\r\n .ThenBy(l0 => l0.Inner.Title)\r\n .Select(l0 => new Tag{ \r\n Id = l0.Outer.TagId, \r\n Title = l0.Inner.Title, \r\n Type = l0.Inner.Type, \r\n IsRemovedFromLO = l0.Outer.IsUntaggedFromLO \r\n }\r\n ))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
I hope it helps:
var examContents = await this._context.ExamContents
.AsNoTracking()
.Where(x => x.IsNewVersion && versionIds.Contains(x.VersionId))
.SelectMany(examContent => examContent.LearningOutcome.learningoutcometags,
(examContent, tag) => new { examContent, tag })
.Select(examContentAndTag => new ExamContentModel
{
Id = examContentAndTag.ExamContent.Id,
VersionId = examContentAndTag.ExamContent.VersionId,
LearningOutcomeId = examContentAndTag.ExamContent.LearningOutcomeId,
SectionId = examContentAndTag.ExamContent.SectionId,
Title = examContentAndTag.ExamContent.LearningOutcome.Title,
AssignedQuestionCount = examContentAndTag.ExamContent.AssignedQuestionCount,
DisplayOrder = examContentAndTag.ExamContent.DisplayOrder,
IsNewVersion = examContentAndTag.ExamContent.IsNewVersion,
questions = examContentAndTag.ExamContent.learningoutcome.questions
.where(x => x.category == questioncategory.certification)
.select(y => new question
{
title = y.title,
category = y.category,
status = y.status,
isdraft = y.isdraft,
publishedquestionid = y.publishedquestionid,
examversionid = y.examversionid
}),
tags = examContentAndTag.tag
.select(t => new tag
{
id = t.tagid,
title = t.tag.title,
type = t.tag.type,
isremovedfromlo = t.isuntaggedfromlo
})
})
.OrderBy(examContentAndTag => examContentAndTag.ExamContent.SectionId)
.ThenBy(examContentAndTag => examContentAndTag.ExamContent.DisplayOrder)
.ThenBy(examContentAndTag => examContentAndTag.tag.type)
.ThenBy(examContentAndTag => examContentAndTag.tag.title)
.ToListAsync();
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.selectmany?view=net-5.0
I have pretty simple LINQ expression
IQueryable<FreeBetDTO> records = UnitOfWork.FreeBets
.Include(f => f.FreeBetCategories)
.Include(f => f.FreeBetCards)
.Where(f => f.FreeBetCards.Any(cards => cards.UserId == request.UserId))
.Select(f => new FreeBetDTO
{
FreeBetId = f.FreeBetId
LineCategories = f.FreeBetCategories
.GroupBy(g => new { g.LineCategoryID, g.Title })
.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.Key.LineCategoryID,
Title = c.Key.Title
}).AsEnumerable()
});
When I am executing it I catch the error:
System.InvalidOperationException: Unable to translate collection subquery in projection since it uses 'Distinct' or 'Group By' operations and doesn't project key columns of all of it's tables which are required to generate results on client side. Missing column: t.ID. Either add column(s) to the projection or rewrite query to not use 'GroupBy'/'Distinct' operation.
at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.
....
The problem is here .GroupBy(g => new { g.LineCategoryID, g.Title }). If I don't group records, the error disappears.
I was trying a lot of cases with GroupBy() and Distinct(). But can't understand why this is happening. Because I just need grouping like this.
Error message says that you have to include Id column in projection. But you can't do that with GroupBy. So rewrite query into two steps (removed not needed includes):
var rawRecords = UnitOfWork.FreeBets
.Where(f => f.FreeBetCards.Any(cards => cards.UserId == request.UserId))
.Select(f => new
{
FreeBetId = f.FreeBetId
LineCategories = f.FreeBetCategories.Select(c => new { c.Id, c.LineCategoryID, c.Title })
.ToList()
})
.AsEnumerable();
var records = rawRecords
.Select(f => new FreeBetDTO
{
FreeBetId = f.FreeBetId
LineCategories = f.LineCategories.GroupBy(g => new { g.LineCategoryID, g.Title })
.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.Key.LineCategoryID,
Title = c.Key.Title
})
});
Similar query, but more optimal:
var query =
from f in UnitOfWork.FreeBets
from c in f.FreeBetCards
where f.FreeBetCards.Any(cards => cards.UserId == request.UserId)
select new { f.FreeBetId, c.LineCategoryID, c.Title };
query = query.Distinct();
var records = query.AsEnumerable()
.GroupBy(f => f.FreeBetId)
.Select(g => new FreeBetDTO
{
FreeBetId = g.Key
LineCategories = g.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.LineCategoryID,
Title = c.Title
})
.AsEnumerable()
});
Why am I getting only one entry in DownTimeDetails list even though in Data we have 3 entries.
VehicleEventDetails Res = dbEntity.DownTimeHeaders
.Join(dbEntity.DownTimeDetails, dth => dth.DownTimeHeaderID, dtd => dtd.DownTimeHeaderID, (dth, dtd) => new { dth, dtd })
.Where(x => x.dth.DownTimeHeaderID == 42)
.GroupBy(gx => gx.dtd.DownTimeDetailID)
.Select(t => new VehicleEventDetails()
{
BookingId = t.Select(a => a.dth.BookingId).FirstOrDefault(),
DownTimeDetails = t.Select(ab => new DownTimeDetails
{
LocalDTStartTime = (DateTime)ab.dtd.LocalDTStartTime,
LocalDTEndTime = (DateTime)ab.dtd.LocalDTEndTime,
CalculatedEventDTReason = ab.dtd.CalculatedEventDTReason,
CalculatedEventDTInMinutes = (int)ab.dtd.CalculatedEventDT,
}).ToList()
}).FirstOrDefault();
You are looking for something like this:
VehicleEventDetails Res = dbEntity.DownTimeHeaders
.Where(x => x.DownTimeHeaderID == 42)
.Select(x => new VehicleEventDetails
{
BookingId = x.BookingId,
DownTimeDetails = x.DownTimeDetails
.Select(dtd=> new DownTimeDetails
{
LocalDTStartTime = (DateTime)dtd.LocalDTStartTime,
LocalDTEndTime = (DateTime)dtd.LocalDTEndTime,
CalculatedEventDTReason = dtd.CalculatedEventDTReason,
CalculatedEventDTInMinutes = (int)dtd.CalculatedEventDT,
})
.ToList()
})
.FirstOrDefault();
Notes:
Using .Join is an anti-Entity Framework pattern. Always try to use navigation properties, they exist for a reason.
Don't use .GroupBy unless you actually need a group. You don't want any grouping in this query.
As a general note, try not to make the expression variable names so confusing.
I want list of all unique Scheme_Codes but I am unable to write query. I tried this one but I am confused what's problem with this query.
var queryresult = db.MFData.GroupBy(x => new { Scheme_Name = x.Scheme_Name, Scheme_Code = x.Scheme_Code, FundFamily = x.FundFamily, Date = x.Date })
.Select(group => new
{
Scheme_name = group.Key.Scheme_Name,
Scheme_Code = group.Key.Scheme_Code,
FundFamily = group.Key.FundFamily,
Date = group.Max(x => x.Date),
count = group.Select( x => x.Scheme_Code).Distinct().Count()
}
).OrderBy(x => x.Scheme_Code);
I have this query but I am not sure how to convert this to linq
SELECT [Scheme_Code],[FundFamily],[Scheme_Name],
MAX([Date]) as LastDate
FROM [MFD].[dbo].[MFDatas]
GROUP BY [Scheme_Code],[Scheme_Name], [FundFamily]
ORDER BY [Scheme_Code]
All you have to do is omit the date from your groupby-clause:
var queryresult = db.MFData.GroupBy(x => new
{
Scheme_Name = x.Scheme_Name,
Scheme_Code = x.Scheme_Code,
FundFamily = x.FundFamily
}).Select(group => new
{
Scheme_name = group.Key.Scheme_Name,
Scheme_Code = group.Key.Scheme_Code,
FundFamily = group.Key.FundFamily,
Date = group.Max(x => x.Date),
count = group.Select(x => x.Scheme_Code).Distinct().Count()
}).OrderBy(x => x.Scheme_Code);