Translate SQL statement with SUM() in Entity - c#

I try to translate this SQL code :
SELECT w.Id, w.LastName, w.FirstName, SUM(d.Price*dt.Number) AS somme
FROM Waiter w
INNER JOIN Client c on w.Id = c.WaiterId
INNER JOIN DisheOnTable dt on c.Id = dt.ClientId
INNER JOIN Dishe d on dt.DisheId = d.Id
GROUP BY w.Id, w.LastName, w.FirstName
ORDER BY somme DESC;
in entity framework.
I tried something like this
var query2 = (from w in db.Waiter
join c in db.Client on w.Id equals c.WaiterId
join dt in db.DisheOnTable on c.Id equals dt.ClientId
join d in db.Dishe on dt.DisheId equals d.Id
group w by new { w.Id, w.LastName, w.FirstName } into g
//orderby g.Select() descending
select new
{
id = g.Key.Id,
lastname = g.Key.LastName,
firstname = g.Key.FirstName,
total = g.Sum(q => q.)
});
but my sum doesn't work (after multiple research and try) and i don't know how to multiply my variables.
PS : The SQL statement works well, i tried it.
Thank you for helping guys ! :)

You need to group on both dish and DishOnTable alias as Price is in Dish and Number is in DishOnTable:
group new{ d,dt} by new {w.Id, w.LastName, w.FirstName} into g
and now sum the columns which you want from it
select new {
id = g.Key.Id,
lastname = g.Key.LastName,
firstname = g.Key.FirstName,
total = g.Sum(q => q.d.Price * q.dt.Number)
}).OrderBy(x=>x.total)

Related

Multiple Left Join with Linq and Defaults Values

I'm trying to write a query that contains multiple left joins in linq in a c# .netcore 2.2 application. I've tried writing the query in linq but it is not properly retrieving all the rows. Query I'm trying to convert is as follows.
select ISNULL(b.Id, '00000000-0000-0000-0000-000000000000') as 'Bat Id', p.Id as 'ProductId', p.RP, u.UnitName as 'UnitName', ISNULL(b.QTY,0) as 'BusQty', p.[Name] as 'Product Name'
from Products p left join Bat b
ON p.Id = b.ProductId
left join Units u on p.UOId = u.Id;
linq I have so far
var allProducts = (from p in _db.Products
join s in _db.Bat on p.Id equals s.ProductId into ps
from s in ps.DefaultIfEmpty()
join u in _db.Units on p.UOId equals u.Id
select new
{
BatId = s.Id == null ? Guid.NewGuid() : s.Id,
RP = p.RP,
BusQty = s.QTY == null ? 0 : s.QTY,
ProductName = p.Name,
UnitName = u.UnitName,
ProductId = p.Id,
}).ToList();
You are missing DefaultIfEmpty() on Units, thereby turning it into an inner join
var allProducts = (
from p in _db.Products
join s in _db.Bat on p.Id equals s.ProductId into ps
from s in ps.DefaultIfEmpty()
join u in _db.Units on p.UOId equals u.Id into us
from u in us.DefaultIfEmpty()
select new
{
BatId = s.Id ?? Guid.NewGuid(),
RP = p.RP,
BusQty = s.QTY ?? 0,
ProductName = p.Name,
UnitName = u.UnitName,
ProductId = p.Id,
}).ToList();

Struggling to convert SQL query to it's LINQ equivalent - Multiple joins, groupings and aggregate functions

I have the following query that gives me expected results in SQL Server Management Studio:
SELECT
u.DisplayName,
up.ColorPreferences,
SUM(rt.Score) AS Points,
COUNT(*) AS Plans,
MAX(pl.Created) AS MaxDate
FROM
[dbo].[Users] u
INNER JOIN
[dbo].[PlanLogs] pl ON u.Id = pl.UserId
INNER JOIN
[dbo].[ResourceTypes] rt ON pl.ResourceTypeId = rt.Id
INNER JOIN
[dbo].[UserProfile] up ON pl.UserId = up.UserId
GROUP BY
u.DisplayName, up.ColorPreferences;
an I have the following working linq query:
from u in _context.Users
join pl in _context.PlanLogs on u.Id equals pl.UserId
join rt in _context.ResourceTypes on pl.ResourceTypeId equals rt.ID
join up in _context.UserProfile on pl.UserId equals up.UserId
group rt by new { u.DisplayName, up.ColorPreferences} into g
select new
{
DisplayName = g.Key.DisplayName,
ColorPrefs = g.Key.ColorPreferences,
Points = g.Sum(x => x.Score),
Plans = g.Count()
};
As you can see, it is missing MaxDate. I can't get access to MaxDate because g contains properties from rt. I've tried the following and i get "Value does not fall within the expected range"
from u in _context.Users
join pl in _context.PlanLogs on u.Id equals pl.UserId
join rt in _context.ResourceTypes on pl.ResourceTypeId equals rt.ID
join up in _context.UserProfile on pl.UserId equals up.UserId
group new { rt, pl } by new { u.DisplayName, up.ColorPreferences} into g
select new
{
DisplayName = g.Key.DisplayName,
ColorPrefs = g.Key.ColorPreferences,
Points = g.Sum(x => x.rt.Score),
Plans = g.Count()
MaxDate = g.Max(m => m.pl.Created)
};
How do i add MaxDate to the results?
Thanks
Have you tried accessing the max value from pl.created on your first linq query? why are you grouping by rt and not the whole result? try this instead :
from u in _context.Users
join pl in _context.PlanLogs on u.Id equals pl.UserId
join rt in _context.ResourceTypes on pl.ResourceTypeId equals rt.ID
join up in _context.UserProfile on pl.UserId equals up.UserId
group u by new { u.DisplayName, up.ColorPreferences} into g
select new
{
DisplayName = g.Key.DisplayName,
ColorPrefs = g.Key.ColorPreferences,
Points = g.Sum(x => x.Score),
Plans = g.Count(),
MaxDate = g.Max(m => m.pl.Created)
};
I solevd this in the end. I needed to pass the specific columns to the group not the whole table:
group new { rt.Score, pl.Created } by..
rather than
group new { rt, pl } by...
Working query:
from u in _context.Users
join pl in _context.PlanLogs on u.Id equals pl.UserId
join rt in _context.ResourceTypes on pl.ResourceTypeId equals rt.ID
join up in _context.UserProfile on pl.UserId equals up.UserId
group new { rt.Score, pl.Created } by new { u.DisplayName, up.ColorPreferences } into g
select new
{
DisplayName = g.Key.DisplayName,
ColorPrefs = g.Key.ColorPreferences,
Points = g.Sum(i => i.Score),
Plans = g.Count(),
MaxCreated = g.Max(i => i.Created).ToString("dd/MM/yyyy HH:mm")
}

How to rewrite sql query to linq

I'm trying to rewrite sql query to linq but can't do it myself.
The most problem for me is to get I,II and III aggregated values.
Sql query:
select o.Name,t.TypeID, SUM(e.I),SUM(e.II),SUM(e.III) from Expenditure e
join Finance f on f.FinanceId = e.FinanceId
join FinanceYear fy on fy.FinanceYearId = f.FinanceYearId and fy.StatusId = 1
join Project p on p.ProjectId = fy.ProjectId
join Organization o on o.OrganizationId = p.OrganizationId
join Type t on t.TypeID = p.TypeID
where fy.Year = 2018
group by o.Name,s.TypeID
and what I have done so far is:
var x = (from e in _db.Expenditures
join f in _db.Finances on e.FinanceId equals f.FinanceId
join fy in _db.FinanceYears on f.FinanceYearId equals fy.FinanceYearId and fy.StatusId = 1 // this does not work, cant join on multiple conditions?
join p in _db.Projects on fy.ProjectId equals p.ProjectId
join o in _db.Organizations on p.OrganizationId equals o.OrganizationId
join s in _db.Types on p.TypeId equals s.TypeId
group new { o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = ?,
II = ?,
III = ?,
}
);
Try something like this:
group new { e, o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = grp.Sum(a => a.e.I),
II = grp.Sum(a => a.e.II),
III = grp.Sum(a => a.e.III),
}
You'll need to adjust the right side of the lambda to navigate to the correct property.
You Need to use the Group by for aggregation methods.
Check the below link for more Knowledge.
How to use aggregate functions in linq with joins?

Join two linq queries on one key column to get one result set

Here I want to join the out put of the first query(one column) to the result of the 2nd query to get a one result set. How can I merge them.(CONCAT doesn't work as required. eg: var query2 = query.concat(query1);)
var query = (from PP in _db.paymentPlans
join APP in _db.Applications on PP.applicationID equals APP.ApplicationId
join C in _db.Courses on APP.courseID equals C.courseID
where PP.active == true && APP.agentID == agentID
orderby C.courseID ascending
group new {C,PP} by new {C.courseID} into totalRecievable
select new PdPpAppCourseModel
{
courseID = totalRecievable.Key.courseID,
totalAmount = totalRecievable.Sum(x => x.PP.totalAmount)
}).ToList();
var query1=(from PD in _db.paymentDetails
join PP in _db.paymentPlans on PD.paymentPlanID equals PP.paymentPlanID
join APP in _db.Applications on PP.applicationID equals APP.ApplicationId
join C in _db.Courses on APP.courseID equals C.courseID
where PP.active == true && APP.agentID == agentID
orderby C.courseID ascending
group new { C,PD } by new { C.courseID, C.cricosCode, C.courseName } into paymentsCourseWise
select new PdPpAppCourseModel
{
courseID = paymentsCourseWise.Key.courseID,
cricosCode = paymentsCourseWise.Key.cricosCode,
courseName = paymentsCourseWise.Key.courseName,
paidAmount = paymentsCourseWise.Sum(x => x.PD.paidAmount)
}).ToList();
You could join query1 and query like this
var result = (from q1 in query1
join q in query on q1.courseID = q.courseID
select new PdPpAppCourseModel
{
courseID = q1.Key.courseID,
cricosCode = q1.Key.cricosCode,
courseName = q1.Key.courseName,
paidAmount = q1.Sum(x => x.PD.paidAmount),
totalAmount = q.totalAmount
}).ToList();

LINQ - multi join with Group by and get average

I'm trying to write this select in LINQ but Im not successful to fix it for long time. I also tried LINQ - join with Group By and get average but it doesn't work in my code. It is obviously that I'm wrong.
SQL:
SELECT name_type, AVG(t.price) as avgPrice FROM type tp
JOIN location l ON l.ID_type = tp.ID
JOIN event e ON e.ID_location = l.ID
JOIN ticket t ON t.ID_event = e.ID
GROUP BY tp.name_type
LINQ:
var q3 = from l in db.location
join tp in db.type on l.ID_type equals tp.ID
join e in db.event on l.ID equals u.ID_location
join t in db.ticket on e.ID equals t.ID_event
group tp by new {Type_name = tp.type_name} into grp
select new
{
Type_name = grp.Key.type_name,
avgPrice = grp.Average( x => x.ticket.price)
};
There are a few problems:
There is an error in the second join—I believe u.ID_location needs to be e.ID_location.
I think you are grouping on the wrong entity, try grouping by t instead of tp.
You don't need the anonymous type in the group by.
Try this:
var results =
from l in db.location
join tp in db.type on l.ID_type equals tp.ID
join e in db.event on l.ID equals e.ID_location
join t in db.ticket on e.ID equals t.ID_event
group t by new tp.type_name into grp
select new
{
Type_name = grp.Key,
avgPrice = grp.Average(x => x.price)
};
If you happen to have navigation properties set up between your entities, this would be a lot easier. It's pretty hard to tell how the entities are supposed to be related, but I'm thinking something like this would work:
// average ticket price per location type
var results =
from t in db.ticket
group t by t.event.location.type.type_name into g
select new
{
Type_name = g.Key,
avgPrice = g.Average(x => x.price)
};
Or in fluent syntax:
var results = db.ticket.GroupBy(t => t.event.location.type.type_name)
.Select(g => new
{
Type_name = g.Key,
avgPrice = g.Average(x => x.price)
});

Categories