I'm trying to convert this linq query to lambda
var query = (from a in context.Table_A
join u in context.Table_B on a.scored equals u.userid
join u2 in context.Table_B on a.scorer equals u2.userid
from cs in a.Table_C //(Table_A is related to Table_C)
where (a.date>= startdate && a.date < enddate)
select new MSViewModel
{
scored= u.User.name,
scorer= u2.User.name,
subject_name = cs.Subject.name,
score = cs.score,
categoryid = cs.id,
})
.AsEnumerable()
.GroupBy(t => t.scored)
.ToList();
so far this is what i have. I'm kinda lost what to do next.
var tobi = db.Table_A.Join(db.Table_B,a=>a.scored,u=>u.userid,
(a,u) => new {scored=u.User.name });
db.Table_A.Join(db.Table_B,a1=>a1.scorer,u2=>u2.userid,
(a,u2)=> new {scorer= u2.User.name});
Firstly, I'd agree with Arran's comment: the query expression is going to be much simpler to deal with. I'm absolutely on board with using the lambda form where it makes sense, but joins are generally much simpler in query expressions.
Having said that, you basically need to imitate transparent identifiers. The code below is untested, but looks vaguely plausible to me.
var query = context.Table_A
.Join(context.Table_B, a => a.scored, u => u.userid,
(a, u) => new { a, u })
.Join(context.Table_B, p => p.a.scorer, u2 => u2.userid,
(p, u2) => new { p, u2 })
.SelectMany(q => q.p.a.TableC, (q, cs) => new { q, cs })
.Where(r => r.q.p.a.date >= startdate && r.q.p.a.date < enddate)
.Select(q => new MSViewModel {
scored= r.q.p.u.User.name,
scorer= r.q.u2.User.name,
subject_name = r.cs.Subject.name,
score = r.cs.score,
categoryid = r.cs.id,
})
.AsEnumerable()
.GroupBy(t => t.scored)
.ToList();
Basically p and q and r are the transparent identifiers here. You've got three of them because you've got two joins and a subsequent from clause.
To expand on my comment, If you have Resharper:
Resharper showing option to convert LINQ to Lambada
After the conversion:
Try this one:
var query = (_context.Table_A.Join(_context.Table_B, a => a.scored, u =>
u.userid,
(a, u) => new {a, u}).Join(_context.Table_B,
#t => #t.a.scorer,
u2 => u2.userid,
(#t, u2) => new {#t, u2}).
SelectMany(#t => _context.Table_A, (#t, cs) => new MSViewModel()
{
scored = #t.#t.u.User.name,
scorer= #t.u2.User.name,
subject_name = #t.cs.Subject.name,
score = #t.cs.score,
categoryid = #t.cs.id,
})).AsEnumerable()
.ToList();
Related
I'm translating a query and here's the original:
select top 5 t.usrID, u.FirstName, u.LastName, t.cnt as sCount
from (
select usrID, COUNT(rID) as cnt
from sessions as s where s.sDate > DATEADD(yy, -1, getdate())
group by usrID
) as t
inner join users as u on t.usrID = u.usrID
order by t.cnt desc
Here's what I have so far:
var topUser = (from p in _context.Sessions
where p.SDate > DateTime.Now.AddYears(-1)
join c in _context.Users on p.UsrId equals c.UsrId into j1
from j2 in j1.DefaultIfEmpty()
// group j2 by p.UsrId into grouped
select new
{
p.UsrId,
j2.FirstName,
j2.LastName,
cnt = p.RId
})
//.OrderBy(d => d.cnt)
//.GroupBy(o => o.UsrId)
.Take(5);
I'm having trouble figuring out how to include count() and group by clauses. When I include groupBy my other columns disappear. Thank you.
This is the answer to your answer - not to your original query. I would put it as comment, but without formatting it's hard to explain
Assuming User object has collection of Session your first statement can be drastically simplified:
var topUsers = _context.Sessions
.Where(s => s.SDate > DateTime.Now.AddYears(-1))
.Select(s => new
{
s.UsrId,
cnt = s.User.Sessions.Count(u => u.UsrId == s.UsrId)
})
.OrderByDescending(s => s.cnt)
.Take(5);
You can shape the results to get a ViewModel that also has FirstName and LastName. It all boils down to defining a model with one-to-many relationship
var topUser = (from p in _context.Sessions
where p.SDate > DateTime.Now.AddYears(-1)
join c in _context.Users on p.UsrId equals c.UsrId into j1
from j2 in j1.DefaultIfEmpty()
group j2 by p.UsrId into g
select new
{
UsrId = g.Key,
FirstName = g.Select(x => x.FirstName).FirstOrDefault(),
LastName = g.Select(x => x.LastName).FirstOrDefault(),
sCount = g.Count()
})
.OrderByDescending(d => d.sCount)
.Take(5);
Alright so it's not the most efficient but it works:
var topUsers = _context.Sessions
.Where(s => s.SDate > DateTime.Now.AddYears(-1))
.GroupBy(s => s.UsrId)
.Select(ws => new { ws.Key, cnt = ws.Count() })
.OrderByDescending(s => s.cnt)
.Take(5);
var topNamedUsers = topUsers.Join(_context.Users, ws => ws.Key, ud => ud.UsrId, (ws, ud) => new { ws.Key, ud.FirstName, ud.LastName, ws.cnt });
I've been puzzling over this problem all morning and can't figure out how to do it in C#.
My SQL query as follows:
select a.CourseID,
a.UserID
from audit a
inner join results r on a.UserID = r.UserID
inner join Course c on a.CourseID = c.CourseID
where c.CourseType = 9 and a.Guid = 'A123F123D123AS123123'
and a.Result = 'Passed' and r.Class = 'Maths'
group by a.CourseID, a.UserID
order by a.UserID
returns exactly what I want, but I can't seem to translate it into linq format. (the format being used here is what is required in my job at the moment so please advise on this format)
So far I have the following:
var audits = auditRepository.Get(a => a.Course.CourseType == 9 && a.GUID == this.Company.GUID && a.Result == "Passed", null, null,
a => a.Course, a => a.User)
.Join(resultsRepository.Get(r => r.GUID == this.Company.GUID && r.Class == class),
a => a.UserID,
r => r.UserID,
(a, r) => new Audit
{
User = a.User,
Course = a.Course,
Result = a.Result,
Timestamp = a.Timestamp,
AuditID = a.AuditID,
UserID = a.UserID
}
)
.OrderByDescending(o => o.Timestamp)
.GroupBy(u => new { u.User, u.Course })
.Select(grp => grp.ToList())
.ToList();
However this returns duplicates.
Any advice is appreciated, thanks
H
Instead of
.Select(grp => grp.ToList())
Select only the first element from each group to exclude duplicates:
.Select(grp => grp.First())
If you need a count also:
.Select(t => new{grp = t.First(),cnt = t.Count()} )
Fix:
.Select(t => new { grp = t.First(), cnt = t.Select(s => s.AuditID).Distinct().Count() })
How can I transform this SQL query to LINQ?
SELECT eg.Name Name, sum(bi.PlannedAmount) Amount
FROM BudgetItem bi, Expense e, ExpenseGroup eg
WHERE Discriminator = 'ExpenseItem' AND
bi.ExpenseId = e.Id AND
e.ExpenseGroupId = eg.id AND
bi.MonthlyBudgetId = 1
GROUP BY eg.Name
So far I've come up with this line:
var result = context
.ExpenseGroups
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
But I still cannot figure out what expression to use to add 'bi.MonthlyBudgetItem = 1'.
Does anybody have an Idea?
Edit #1:
I forgot to mention the relationships between the entities. Every ExpenseGroup has many Expenses, and every Expense has many BudgetItems.
So, ExpenseGroup => Expenses => BudgetItems
Edit #2:
I'm using Entity Framework and every ExpenseGroup has a Collection of Expense objects (every Expense has a ExpenseGroup object), as well as every Expense has a Collection of BudgetItem objects (every BudgetItem object has a Expense object).
I suppose something like this should do it:
var result = context
.ExpenseGroups
.Where(x => x.Discriminator == 'ExpenseItem' &&
x.bi.ExpenseId == e.Id &&
x.e.ExpenseGroupId == eg.id &&
x.bi.MonthlyBudgetId == 1)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
Something similar to this...
var result = (from g in context.ExpenseGroups
where g.Expense.BudgetItem.MonthlyBudgetId == 1
select g)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
or
var result = context.ExpenseGroups
.Where(g => g.Expense.BudgetItem.MonthlyBudgetId == 1)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
You are actually doing an inner join in your SQL query, so do similarly in your linq query as well. This should work:-
var result = from bi in context.BudgetItem
join e in context.Expense
on bi.ExpenseId equals e.Id
where bi.MonthlyBudgetId == 1
join eg in ExpenseGroup
on e.ExpenseGroupId equals eg.id
group new { bi, eg } by eg.Name into g
select new
{
Name = g.Key,
Amount = g.Sum(x => x.bi.PlannedAmount)
};
I have a SQL Query
select Firma.Name as companyName,
Taetigkeit.Taetigkeit as skillName,
SUM(Zeit) as time
from Zeiterfassung
inner join Firma On ZEiterfassung.FirmenID = Firma.ID
inner join Taetigkeit on Zeiterfassung.TaetigkeitID = Taetigkeit.ID
group by Taetigkeit, Firma.Name
order by Firma.Name
And want to "translate" it to linq. Here is what I tried:
var query = db.Zeiterfassung
.Where(x => x.Firma.ID == x.FirmenID && x.TaetigkeitID == x.Taetigkeit.ID)
.GroupBy(x => x.Taetigkeit.Taetigkeit1)
.Select(x => new Evaluation() { skillName = x.Key, time = x.Sum(y => y.Zeit), //skillName = x.Sum(x => x.Zeit), })
.OrderBy(x => x.skillName);
I dont know who to solve this with joins and the group by because all the time when i do a groupBy i cant access the other members.
From data you provided, I think query should look like
from z in db.Zeiterfassung
join f in db.Firma on z.FirmenID equals f.ID
join t in db.Taetigkeit on z.TaetigkeitID equals t.ID
select new { f.Name, t.Taetigkeit, z.Zeit) into x
group x by new { x.Taetigkeit, f.Name } into g
select new {
CompanyName = g.Key.Name,
SkillName = g.Key.Taetigkeit,
Time = g.Sum(i => i.Zeit)
}
Or with navigation properties:
db.Zeiterfassung
.Select(z => new { z.Zeit, z.Taetigkeit.Taetigkeit1, z.Firma.Name })
.GroupBy(x => new { x.Taetigkeit1, x.Name })
.Select(g => new Evaluation {
companyName = g.Key.Name,
skillName = g.Key.Taetigkeit1,
time = g.Sum(y => y.Zeit)
});
I decided to try my hand at LINQ and so far its been a miserable failure. I need to convert the following SQL query to LINQ:
SELECT
MAX(A.NEXTPAYMENTDATE) as NextPaymentDate
, SUM(B.PurchasePrice) - SUM(A.Amount) AS BALANCE
, c.FirstName
, c.LastName
, b.[year]
, b.make
, b.model
FROM Payments A
JOIN Vehicles B ON A.VehicleId = B.Id
JOIN Customers C ON b.CustomerId = c.Id
GROUP BY VehicleId, c.FirstName, c.LastName, b.[year], b.make, b.model
HAVING SUM(B.PurchasePrice) - SUM(A.Amount) > 0
This is what I have so far. It seems to work to a certain extent, but I don't know how to progress from here.
var groupedpayments =
from payments in db.Payments
group payments by new { payments.VehicleId }
into paymentGroup
let maxDate = paymentGroup.Max(x => x.NextPaymentDate)
let paid = paymentGroup.Sum(x => x.Amount)
select
new { Payments = paymentGroup.Where(x => x.NextPaymentDate == maxDate)};
I think that is what you need.
var query =
Payments.Join(Vehicles, p => p.VehicleId, v => v.Id, (p, v) => new {p, v})
.Join(Customers, d => d.v.CustomerId, c => c.Id, (d, c) => new {d, c})
.GroupBy(r =>
new {
r.d.p.VehicleId,
r.d.v.year,
r.d.v.make,
r.d.v.model,
r.c.FirstName,
r.c.LastName
},
(g, data) =>
new {
FirstName = g.FirstName,
LastName = g.LastName,
Year = g.year,
Make = g.make,
Model = g.model,
NextPaymentDate = data.Max(dd => dd.d.p.NEXTPAYMENTDATE),
Balance = data.Sum(dd => dd.d.v.PurchasePrice)
- data.Sum(dd => dd.d.p.Amount)})
.Where(r => r.Balance > 0);