I have a SQL command that I am trying to convert to a LINQ to SQL command, but am having difficulties.
My SQL command follows:
SELECT purchs.iclientid, ifeatureid, AddnlOptionList FROM purchs
WHERE AddnlOptionList <> ''
GROUP BY purchs.iclientid, ifeatureid, AddnlOptionList
HAVING (SUM(noptions) > 0)
I've managed to get this far following examples:
var q =
from purchs in db.Purchases
group q by purchs.noptions into g
where purchs.AddnlOptionList != ""
&& g.Sum(x => x.noptions) > 0
select q;
However, I seem to be stuck on group q with the following two errors:
Cannot use local variable 'q' before it is declared
Cannot convert lambda expression to type 'System.Collections.Generic.IEqualityComparer<decimal?> because it is not a delegate type
An example from here says that this should work, although it uses a join, and I am not. Any help would be appreciated.
SOLUTION
I had to modify Xiaoy312's code a little bit to get what I wanted, so I figured I would post it here in hopes that it might help someone in the future. Thank you #Xiaoy312 for the help.
var updates = db.Purchases
.Where(p => p.AddnlOptionList != "")
.GroupBy(p => new { p.iclientid, p.ifeatureid, p.AddnlOptionList })
.Where(g => g.Sum(p => p.noptions) > 0)
.Select(g => g.Key);
You can't put both the WHERE and HAVING clause into a single where. I'm less familiar with the other syntax, so here is the method syntax one :
var results = db.Purchases
.Where(p => p.AddnlOptionList != "")
.GroupBy(p => new { p.notions, p.iclientid, p.ifeatureid })
.Where(g => g.Sum(p => p.notions) > 0)
.SelectMany(g => g)
EDIT: converted to Linq syntax.
var results = from p in db.Purchases
where p.AddnlOptionList != ""
group p by new { p.notions, p.iclientid, p.ifeatureid } into g
where g => g.Sum(p => p.notions) > 0
from p in g
select p;
EDIT: I've miss read the sql command. It meant to only pull the groups, not every item in each group.
// method syntax
db.Purchases
.Where(p => p.AddnlOptionList != "")
.GroupBy(p => new { p.notions, p.iclientid, p.ifeatureid })
.Where(g => g.Sum(p => p.notions) > 0)
.Select(g => g.Key)
// query syntax
from p in db.Purchases
where p.AddnlOptionList != ""
group p by new { p.notions, p.iclientid, p.ifeatureid } into g
where g.Sum(p => p.notions) > 0
select new { g.Key.notions, g.Key.iclientid, g.Key.ifeatureid };
Related
I have a problem with below exception:
When called from 'VisitLambda', rewriting a node of type
'System.Linq.Expressions.ParameterExpression' must return a non-null
value of the same type. Alternatively, override 'VisitLambda' and
change it to not visit children of this type.
it is related to this part of the code:
var teamEntries = _dataContext.TeamEntriesEntries
.Where(c => TeamEntryIds.Contains(c.Id))
.Include(c => c.TeamType);
.Select(c => new
{
UserId = filteredCachedEntries.Any() ? filteredCachedEntries.Where (f => f.CurrentCalendarEntry != null && f.CurrentCalendarEntry.Id == c.Id).FirstOrDefault().UserId : 0,
c.TeamType,
Status = c.Progress != null ? c.Progress.Status : null,
})
.ToList();
Below line cause error (Where):
UserId = filteredCachedEntries.Any() ? filteredCachedEntries.Where (f => f.CurrentCalendarEntry != null && f.CurrentCalendarEntry.Id == c.Id).FirstOrDefault().UserId : 0
in .net core 2.2 everything was ok but right now it doesn't work and show me exceptaion.
Extract the data you need from the server and then do client side processing on the client side data:
var teamEntries = _dataContext.TeamEntriesEntries
.Where(c => TeamEntryIds.Contains(c.Id))
.Select(c => new {
cID = c.Id,
c.TeamType,
Status = c.Progress.Status,
})
.AsEnumerable() // switch to client side processing
.Select(c => new {
UserId = filteredCachedEntries
.Where(f => f.CurrentCalendarEntry.Id == c.cID)
.Select(f => f.UserId)
.FirstOrDefault(),
c.TeamType,
c.Status
})
.ToList();
Well, query is wrong. EF Core 2.2 just evaluates everything on the client in that case. Removed everything that is not needed for correct SQL translation.
var teamEntries = _dataContext.TeamEntriesEntries
.Where(c => TeamEntryIds.Contains(c.Id))
.Select(c => new
{
UserId = filteredCachedEntries
.Where(f => f.CurrentCalendarEntry.Id == c.Id)
.Select(f => f.UserId)
.FirstOrDefault(),
c.TeamType,
Status = c.Progress.Status,
})
.ToList();
Variant via LEFT JOIN
var teamEntries =
from c in _dataContext.TeamEntriesEntries
where TeamEntryIds.Contains(c.Id)
from f in filteredCachedEntries
.Where(f => f.CurrentCalendarEntry.Id == c.Id)
.Take(1)
.DefaultIfEmpty()
select new
{
UserId = f.UserId,
c.TeamType,
Status = c.Progress.Status,
})
.ToList();
Here's the code I have:
var a = Times
.Where(x => Int32.Parse(x.DateYYMMDD) > Int32.Parse("200309"))
.GroupBy(x => x.DateYYMMDD)
.OrderBy(g => g.Key)
.Select(g => new ScreenTimeModel
{
DateYYMMDD = $"20{g.Key.Substring(0, 2)}/{g.Key.Substring(2, 2)}/{g.Key.Substring(4, 2)}"
})
.Select(g => new ScreenTimeModel
{
DateYYMMDD = (g => g.DateYYMMDD),
})
It's simplified but what I would like to do is some processing of the value of DateYYMMDD that's put into the first .Select.
I tried to get that data with this (g => g.DateYYMMDD) but it's not working.
Can someone tell me how I can get references to the DateYYMMDD in the first select?
Try to remove the first Select method and update the second a little bit, to get a ScreenTimeModel with DateYYMMDD assigned to the group key
.Select(g => new ScreenTimeModel
{
DateYYMMDD = g.DateYYMMDD,
}
in your current code the first Select get the IGrouping<TKey,TElement> as g parameter, in the second Select parameter g is ScreenTimeModel. I don't think that you will need to call it twice
I have the following code where I get error when loading Peers:
Value cannot be null. Parameter name: source
I am using FirstOrDefault and DefaultIfEmpty methods, and inside the select statement I am also checking if the object is empty m => m == null ?. But, I cannot avoid the error. Any ideas?
ReviewRoundDTO_student results = _context.ReviewRounds
.Include(rr => rr.ReviewTasks).ThenInclude(rt => rt.ReviewTaskStatuses)
.Include(rr => rr.Submissions).ThenInclude(s => s.PeerGroup.PeerGroupMemberships).ThenInclude(m => m.User)
.Include(rr => rr.Rubric)
.Where(rr => rr.Id == reviewRoundId)
.Select(rr => new ReviewRoundDTO_student
{
Id = rr.Id,
SubmissionId = rr.Submissions.FirstOrDefault(s => s.StudentId == currentUser.Id).Id,
Peers = rr.Submissions.FirstOrDefault(s => s.StudentId == currentUser.Id)
.PeerGroup.PeerGroupMemberships.DefaultIfEmpty()
.Select(m => m == null ? new ApplicationUserDto { } : new ApplicationUserDto
{
//FullName = m.User.FullName,
//Id = new Guid(m.UserId)
}),
}).FirstOrDefault();
Try avoiding FirstOrDefault().Something construct - expression trees do not support ?. operator which you'd normally use in similar LINQ to Objects query, and EF Core currently has issues translating it correctly - if you look at the exception stack trace, most likely the exception is coming deeply from EF Core infrastructure with no user code involved.
I would recommend rewriting the LINQ query w/o such constructs, for instance something like this:
var results = _context.ReviewRounds
.Where(rr => rr.Id == reviewRoundId)
.Select(rr => new ReviewRoundDTO_student
{
Id = rr.Id,
SubmissionId = rr.Submissions
.Where(s => s.StudentId == currentUser.Id)
.Select(s => s.Id)
.FirstOrDefault(),
Peers = rr.Submissions
.Where(s => s.StudentId == currentUser.Id)
.Take(1)
.SelectMany(s => s.PeerGroup.PeerGroupMemberships)
.Select(m => new ApplicationUserDto
{
FullName = m.User.FullName,
Id = m.UserId
})
.ToList(),
})
.FirstOrDefault();
Note that Include / ThenInclude are not needed in projection queries, because they are ignored.
I have a line like so:
var lstOfIds = db.TBL_AssocIncidentSpecialCat
.Where(x => x.IncidentId == incidentVm.ID)
.Select(t => t.SpecialCategoriesId)
.ToList();
This line gathers me a list of of the SpecialCategoriesIds. Then I have to do this:
incidentVm.LstSpecialCategories = db.TBL_SpecialCategories
.Where(x => lstOfIds.Contains(x.Id))
.Select(t => t.SpecialCategory)
.ToList();
Is there a way to combine these two lines into one? Even though it's only two lines of code.. I feel as though having to grab the Ids first then having to grab the associated property based on the Id is just an extra step and could be shortened to just one line. But I may be wrong.
Any help is appreciated.
UPDATE
incidentVm.LstSpecialCategories = db.TBL_AssocIncidentSpecialCat
.Where(x => x.IncidentId == incidentVm.ID)
.Join(
db.TBL_SpecialCategories,
x => new{Id = x.SpecialCategoriesId},
t => new{Id = t.Id},
(x,t) => {return t.SpecialCategory}
);
I am getting red squiggly under last part in Join:
A lambda expression with a statement body cannot be converted to an expression tree
You can combine the two lines using Join. Something like,
var result = db.TBL_AssocIncidentSpecialCat
.Join(
db.TBL_SpecialCategories,
ais => new { Id = ais.IncidentId },
sc => new { Id = sc.Id },
(ais, sc) => { return sc; }
)
.ToList();
C# Fiddle for this.
Update with Where Clause: You should use your Where condition after the Join.
var result = db.TBL_AssocIncidentSpecialCat
.Join(
db.TBL_SpecialCategories,
ais => new { Id = ais.IncidentId },
sc => new { Id = sc.Id },
(ais, sc) => new { ais = ais, sc = sc }
)
.Where(x => x.ais.IncidentId == 1)
.Select(y => y.sc)
.ToList();
You can try a LINQ query-style join:
incidentVm.LstSpecialCategories = (from aispc in db.TBL_AssocIncidentSpecialCat
join spc in db.TBL_SpecialCategories
on aispc.SpecialCategoriesId equals lspc.Id
where aispc.IncidentId == incidentVm.ID
select lspc.SpecialCategory).ToList();
I was able to figure this out with the help of some answers and me testing it on my own. Here is my solution:
incidentVm.LstSpecialCategories = db.TBL_AssocIncidentSpecialCat
.Where(t => t.IncidentId == incidentVm.ID)
.Join(db.TBL_SpecialCategories,
ik => ik.SpecialCategoriesId,
ok => ok.Id,
(ik, ok) => ok.SpecialCategory
)
.ToList();
Thank you for all of your help.
I have below stated 2 tables:
now I want to get the set of Child Table objects for whichever their parent table entries are latest(wr.r.t lastmodified). It should be something like....
List<Child_Table> List = ChildsList.Where(x=>x.name =="pqr" && status == "done")
.Select(x=>x.Parent.lastmodified == recent record).....ToList();
You can use GroupBy on the date, then OrderByDescending on the Key then take the First followed by SelectMany to flatten the results.
var result = ChildsList.Where(x => x.name == "pqr" && x.status == "done")
.GroupBy(x => x.Parent.lastmodified)
.OrderByDescending(g => g.Key)
.First()
.SelectMany(g => g)
.ToList();
You could use a join to accomplish it:
var results = children
.Join(parents.OrderByDescending(p => p.lastmodified).Take(1),
c => c.parent_id,
p => p.id,
(c, p) => c)
.Where(x => x.name == "pqr" && x.status == "done")
.ToList();