LINQ: Using INNER JOIN, Group and SUM - c#

I am trying to perform the following SQL using LINQ and the closest I got was doing cross joins and sum calculations. I know there has to be a better way to write it so I am turning to the stack team for help.
SELECT T1.Column1, T1.Column2, SUM(T3.Column1) AS Amount
FROM T1
INNER JOIN T2
ON T1.T1ID = T2.T1ID
INNER JOIN T3
ON T2.T3ID = T3.T3ID
GROUP BY T1.Column1, T1.Column2
What I have been trying is the following LINQ code
var qTotal = from T2 in context.T2
from T3 in context.T3
where T3.T3ID == T3.T3ID
group T3 by T2.T1ID into gT2T3
from T1 in context.T1
where gT2T3.Key.Equals(T1.T1ID)
select new { T1.Column1,T1.Column2,Amount = gT2T3.Sum(t => t.Column1)};
I know there has to be a better way to write it, I just do not know how, any help would be great!

Try this:
var total = from T1 in context.T1
join T2 in context.T2 on T1.T2ID equals T2.T2ID
join T3 in context.T3 on T2.T3ID equals T3.T3ID
group T3 by new { T1.Column1, T1.Column2 } into g
select new {
Column1 = T1.Column1,
Column2 = T2.Column2,
Amount = g.Sum(t3 => t3.Column1)
};

For me (using 4.0), the following works.
var total = from T1 in context.T1
join T2 in context.T2 on T1.T2ID equals T2.T2ID
join T3 in context.T3 on T2.T3ID equals T3.T3ID
group T3 by new { T1.Column1, T1.Column2 } into g
select new {
Column1 = g.Key.Column1,
Column2 = g.Key.Column2,
Amount = g.Sum(t3 => t3.Column1)
};

Below code is working for me :
var credit = (from bm in BulkMessage
join sms in SMS on bm.BulkMessageId equals sms.BulkMessageId
where bm.ProfileId == pid && bm.IsActive == true
group sms by sms.SMSCredit into g
select new { SMSCredits = g.Sum(s => s.SMSCredit) }).FirstOrDefault();

Related

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?

convert Conditional Join in SQL to Linq

I have a normally simple looking query in SQL as:
SELECT table1.Id, count(table2.col) AS OrderCol
FROM table1
LEFT JOIN table2 ON table1.Id = table2.Id
LEFT JOIN table3 ON table2.Id = table3.Id AND table2.condition = 3 //some integer value
GROUP BY table1.Id
ORDER BY count(table2.col) DESC
When AND clause appears inside join, I am not sure about how to convert this to LINQ...
How to achieve it?
It goes something like:
from t1 in db.Table1
join t2 in db.Table2 on t1.field equals t2.field
select new { t1.field2, t2.field3}
Try this:
var answer = (from t1 in table1
join t2 in table2 on t1.Id equals t2.Id into subData1
from t2sub in subData1.DefaultIfEmpty()
join t3 in table3 on new { Id = t2sub == null ? 0 : t2sub.Id, condition = t2sub == null ? 0 : t2sub.condition } equals new { t3.Id, condition = 3 } into subData
from t3sub in subData.DefaultIfEmpty()
group new { t1, t2sub } by t1.Id into subGroup
orderby subGroup.Count(x => x.t2sub != null) descending
select new {
Id = subGroup.Key,
OrderCol = subGroup.Count(x => x.t2sub != null)
}).ToList();

Linq - Inner Join not retrieving all records from left table

I have done an inner join, it shows only the matching record with following query :-
var data = from t1 in ctx.tblEmp
join t2 in ctx.tblHelp
on t1.Field equals t2.Fld
where t1.Id == Id &&
t2.Id == Id
select new Settings { Master = t1.Labelname, OrderNo = t2.OrderNo};
I want all the records from tblEmp & only matching records from tblHelp.
How to do this?
Use as
var data = from t1 in ctx.tblEmp
join t2 in ctx.tblHelp
on t1.Field equals t2.Fld into u
from t2 in u.DefaultIfEmpty()
where t1.Id == Id &&
t2.Id == Id
select new Settings { Master = t1.Labelname, OrderNo = t2.OrderNo};
Try this
var data = from t1 in ctx.tblEmp
join t2 in ctx.tblHelp
on t1.Field equals t2.Fld into u
from t2 in u.DefaultIfEmpty()
where t1.Id == Id
orderby columnname // Added Order By
select new Settings { Master = t1.Labelname, OrderNo = t2.OrderNo==null ?"":t2.OrderNo};
var query = from t1 in ctx.tblEmp
join t2 in ctx.tblHelp on t1 equals t2.Fld into tempGroup
from subpet in tempGroup.DefaultIfEmpty()
select new { t1.Labelname, OrderNo = (subpet == null ? String.Empty : subpet.OrderNo) };

LEFT JOIN with OR condition in LINQ

I need to write following T-SQL in LINQ:
SELECT T1.ID, T2.Name
FROM T1
LEFT JOIN T2 ON (T1.ID = I2.ID1 OR T1.ID = T2.ID2)
An OR-join would look like this in LINQ:
T1.Join(T2, t1=>new{}, t2=>new{}, (t1,t2)=>new{ID=t1.Id, t2=t2}).Where(o=>o.Id == o.t2.Id1 || o.Id==o.t2.Id2);
But that query is an INNER JOIN, not a LEFT JOIN.
Some kind of LEFT JOIN would look like this:
T1.GroupJoin(T2, t1 => t1.Id, t2 => t2.Id1, (t1, t2) => new { Id = t1.Id, Name1 = t2.Select(t => t.Name) }).DefaultIfEmpty()
.GroupJoin(T2, o => o.Id, t2 => t2.Id2, (i, j) => new { Id = i.Id, Name1 = i.Name1, Name2 = j.Select(t => t.Name) }).DefaultIfEmpty();
This query produces correct results, but makes 2 joins instead of 1. Or is it really equivalent to original T-SQL?
Does anybody know how to rewrite this query better?
This answer from a similar question gives us an easy way to write LEFT JOINs:
https://stackoverflow.com/a/4739738/1869660
var query = from t1 in T1
from t2 in T2.Where(tt2 => (t1.ID == tt2.ID1) || (t1.ID = tt2.ID2))
.DefaultIfEmpty()
select new { t1.ID, t2.Name }
To solve this with single linq, try using cross join
var results = (from a in test1
from b in test2
where a.ID == b.ID1 || a.ID == b.ID2
select new {x = a.ID, y = b.Name});
var LeftJoin = from emp in ListOfEmployees
join dept in ListOfDepartment
on emp.DeptID equals dept.ID into JoinedEmpDept
from dept in JoinedEmpDept.DefaultIfEmpty()
select new
{
EmployeeName = emp.Name,
DepartmentName = dept != null ? dept.Name : null
};

SQL query to LINQ expression

I cannot make the following query into LINQ expression. Could you help me ?
SELECT Employee_Id_FK from TimeRegistrations as tr
JOIN Employees em ON tr.Employee_Id_FK = em.id
JOIN Managers m ON em.Manager_Id_FK = m.id
WHERE m.id = 4
This is what I have so far :
var result = from t in DB.TimeRegistrations
join Employees in DB.TimeRegistrations on t.Employee_Id_FK equals Employees.id
join Managers in DB.Managers on ..... ;
// Display results.
foreach (var r in result)
{
Console.WriteLine(r);
}
In case your db has foreign keys:
var result =from t1 in DB.TimeRegistrations
join t2 in t1.Employees
join t3 in t2.Managers
where t3.id == "4"
select t1
in case it does not:
var result =from t1 in DB.TimeRegistrations
join t2 in DB.Employees on t1.Employee_Id_FK equals t2.id
join t3 in DB.Managers on t2.id equals t3.Manager_Id_FK
where t3.id == "4"
select t1
However shorter way will be:
var result = DB.Managers.Find(4).Employees.SelectMany(e=>e.TimeRegistrations)
Or not that straight forward way:
var result = DB.TimeRegistrations
.Where(t=>t.Employees.Any(e=>e.Managers.Any(m=>m.id == 4)))

Categories