Linq to SQL - Query with multiple joins, sum, grouping, having - sql

I have the following query that I would like to translate to linq.
SELECT
SUM(Credits.CreditAmount)
,Transactions.Id
,Person.FullName
,Person.Id
FROM
Person
JOIN
Transactions
ON Person.AccountId = Transactions.AccountId
JOIN Credits
ON Transactions.Id = Credits.TransactionId
WHERE
Person.Type = 'AccountHolder'
AND Person.Status = 'Active'
AND Transactions.CancelledDate IS NULL
AND Credits.CancelledDate IS NULL
GROUP BY Transactions.AccountId, Person.FullName, Person.Id
HAVING SUM(Credits.CreditAmount) > 20
This is what I came up with. It's an absolute pig... The SQL it generates must be awful.
var query = from p in Person
join t in Transactions
on p.AccountId equalas t.AccountId
join c in Credits
on t.TransactionId = c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
let sumC = grp.Select(x => x.CreditAmount).Sum()
select new
{
TotalCredit = sumC,
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
query.Where(p => p.TotalServiceCredit > 20);
The SQL query runs in approximately 3 seconds but I have yet to find the patience to let the Linq query finish. I was wondering if there is something different I should be doing to accomplish this "group, sum, having" query I'm trying to write? Is there something I can do to help Linq generate more performat SQL?
UPDATE
Turns out sgmoore had the right idea. The key to the performance issue was in his answer.
The difference between this
let sumC = grp.Select(x => x.CreditAmount).Sum()
and this
TotalCredit = grp.Sum(x => x.CreditAmount)
was the difference between a query that finishes and one that does not.
See my revised LINQ query below which completes in about the same time as the SQL (5.3 seconds for SQL vs 5.6 seconds for LINQ).
var query = from p in Person
join t in Transactions
on p.AccountId equalas t.AccountId
join c in Credits
on t.TransactionId = c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
select new
{
TotalCredit = grp.Sum(x => x.CreditAmount),
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
query.Where(p => p.TotalServiceCredit > 20);
Thanks for all your help!

I don't disagree with WEI_DBA's comment but if you need to do this, then you might find it easier to break this into several queries, eg
var query1 = from p in Person
join t in Transactions on p.AccountId equals t.AccountId
join c in Credits on t.TransactionId equals c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
select new { c.CreditAmount, t.AccountID, p.FullName, p.Id};
var query2 = (from p in query1
group p by new { p.AccountId, p.FullName, p.Id } into grp
select new
{
TotalCredit = grp.Sum(x => x.CreditAmount),
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
var query3 = (from p in query2 where p.TotalCredit > 20 select p);
Then you can let LINQ combine this into one sql command.
As always, it is a good idea to check and verify the actual TSQL generated.

Related

where clause subquery in LINQ

I am trying to convert my SQL syntax to the LINQ query , And I have a problem with a subquery.
I want to select max date-time with an Id in a table as a subquery for another select command but I don't know what's right or wrong with this below code.
what I have in Sql
select ap.* ,aph.Lat as 'personLat',aph.Lng as 'personLng',l.cityId,l.Lat as 'LifecenterLat',l.lng as 'LifecenterLng',l.Id as 'LifeCenterId'
from Applicant ap
inner join ApplicantAddressHistory aph on ap.Id = aph.ApplicantId
inner join LifePlusCenter l on aph.CityId = l.CityId
Where ap.FamilyRoleTypeId = '82e26080-fda6-4396-946c-40d0e267f1f3' and aph.CreatedDate in (select max(CreatedDate) from ApplicantAddressHistory
where ApplicantAddressHistory.ApplicantId = ap.Id)
order by ap.NationalityCode
And what I have tried in linq
var innerJoinMultipleTables = from app in db.Applicant.Where(x => x.FamilyRoleTypeId == Guid.Parse("82e26080-fda6-4396-946c-40d0e267f1f3"))
join aph in db.ApplicantAddressHistory on app.Id equals aph.ApplicantId
where aph.CreatedDate == db.ApplicantAddressHistory.Max(x => x.CreatedDate && x.Id=aph.Id)
join l in db.LifePlusCenter on aph.CityId equals l.CityId
let centerLat = l.Lat
let centerLng = l.Lng
orderby app.NationalityCode
select new { app, aph.Lat, aph.Lng, l.CityId, l.Branch, centerLat, centerLng };
without this below line of code ,my linq works correctly.
where aph.CreatedDate == db.ApplicantAddressHistory.Max(x => x.CreatedDate && x.Id=aph.Id)
I need something like this below code in Linq as a subquery
select max(CreatedDate) from ApplicantAddressHistory where ApplicantAddressHistory.ApplicantId = '9836CEC4-EDCB-492C-9899-DF4279210CD2'
I finally tried this and it workd but dont know its correct way or not?!
var innerJoinMultipleTables = from app in db.Applicant.Where(x => x.FamilyRoleTypeId == Guid.Parse("82e26080-fda6-4396-946c-40d0e267f1f3"))
join aph in db.ApplicantAddressHistory on app.Id equals aph.ApplicantId
let rept_max = (from c in db.ApplicantAddressHistory
where c.Id == app.Id
select c.CreatedDate).Max()
where aph.CreatedDate == rept_max
join l in db.LifePlusCenter on aph.CityId equals l.CityId
let centerLat = l.Lat
let centerLng = l.Lng
orderby app.NationalityCode
select new { app, aph.Lat, aph.Lng, l.CityId, l.Branch, centerLat, centerLng };
Am not sure how it works in Linq, but you can modify your query like below to get latest details as per CreatedDate for each ApplicantId.
select ap.* ,aph.Lat as 'personLat',aph.Lng as 'personLng',l.cityId,l.Lat as 'LifecenterLat',l.lng as 'LifecenterLng',l.Id as 'LifeCenterId'
from Applicant ap
inner join
(select *
from
(select *,row_number() over(partition by ApplicantId order by CreatedDate desc) rw
from ApplicantAddressHistory
) p
where p.rw=1
) aph
on ap.Id = aph.ApplicantId
inner join LifePlusCenter l
on aph.CityId = l.CityId
Where ap.FamilyRoleTypeId = '82e26080-fda6-4396-946c-40d0e267f1f3'
/*
and aph.CreatedDate in (
select max(CreatedDate) from ApplicantAddressHistory
where ApplicantAddressHistory.ApplicantId = ap.Id
)
*/
order by ap.NationalityCode
Finally I came up to :
var z = from app in db.Applicant
join aph in db.ApplicantAddressHistory on app.Id equals aph.ApplicantId
join l in db.LifePlusCenter on aph.CityId equals l.CityId
let createDate = app.ApplicantAddressHistory.Max(c => c.CreatedDate)
where createDate.HasValue && aph.CreatedDate == createDate
&& app.FamilyRoleTypeId == Guid.Parse("82e26080-fda6-4396-946c-40d0e267f1f3")
let personLat = aph.Lat
let personLng = aph.Lng
let centerId = l.Id
let LifecenterLat = l.Lat
let LifecenterLng = l.Lng
orderby app.NationalityCode
select new { app, aph, l, app.Id, l.CityId, centerId, personLat, personLng, LifecenterLat, LifecenterLng };

join, group by and count sql to linq conversion

Query:
SELECT COUNT(*) as Avalied
FROM LeaveMaster as lm
JOIN LeaveSubsidary as ls
ON lm.TransMasterId = ls.TransMasterId
WHERE lm.SystemCode = 'abc123' AND lm.EmployeeCode = '0014' AND lm.Status ='Approved'
Group by ls.Leave_Type
How would you convert the above sql query to linq? Thanks :)
Edit :
from p in db.PY_LeaveTransactionMasterTAB.AsEnumerable()
join e in db.PY_LeaveTransactionSubsidaryTAB.AsEnumerable() on p.LV_TransMasterId equals e.LV_TransMasterId into grp
where p.SystemCode == SysCode && p.EmployeeCode == EmpCode && p.Status == "Approved"
group grp by e.Leave_Type // This line is invalid Why?
The above is what I have tried so far, why can't I do e.Leave_Type or what is the right way to do group grp by e.Leave_Type?
You could try this:
(from p in db.PY_LeaveTransactionMasterTAB
join e in db.PY_LeaveTransactionSubsidaryTAB on p.LV_TransMasterId equals e.LV_TransMasterId
where p.SystemCode == SysCode && p.EmployeeCode == EmpCode && p.Status == "Approved"
group new {p,e} by new {e.Leave_Type } into gr
select new
{
Leave_Type = gr.Key.Leave_Type ,
Count = gr.Count()
}).ToList();

Change to linq left join query

SELECT I.*, SI.SupplierID FROM item I
LEFT JOIN SupplierItem SI ON I.ItemID = SI.ItemID AND I.Price = SI.Price
WHERE I.CurrentQty <= I.ReorderLevel and SI.SupplierID = 'AlPA'
how can i change that sql query to Linq Query.
The below query will convert your Sql query to Linq query
var data =
from row in db.item
join row1 in db.SupplierItem
on new { ID= row.ItemID , Price = row.Price }
equals new { ID= row1.ItemID , Price = row1.Price } into joinedData
from row2 in joinedData.DefaultIfEmpty()
where row.CurrentQty <= row.ReorderLevel && row2.SupplierID == "AlPA"
select new {
item = row,
SupplierID = row2.SupplierID
};

Sql query to linq convert

Can anyone help me to translate my sql query to linq? I am not so good in linq can anyone help me out with it please .
select
s.UploadFilename ,
a.ID,
isnull(s.Status_id,1) as 'Status_id' ,
a.CaseID,
a.RecordType,
a.ColumnName,
a.FieldName,
a.OldValue,
a.NewValue,
a.ModifiedBy,
A.ModifiedOn,
isnull(u.UserName,'') as 'UserName'
from [dbo].[AuditTrail] as A
left join Case_Status as s
on s.Case_Id=A.CaseID
left join [dbo].[User] as u
on a.ModifiedOn =u.UserID
where A.CaseID=5338
This is not the answer, my query is big, it was not accepting this query as comment.
This query is not returning records :
var AuditTrailFile = (from AT in db.AuditTrails
join ATCS in db.AssnAuditTrailCaseStatus
on new {ID = AT.ID} equals new { ID = (int)(ATCS.AuditTrialID) }
into ATCS_join
from ATCS in ATCS_join.DefaultIfEmpty()
join CS in db.Case_Status on new { Case_StatusId = (int)(ATCS.CaseStatusID) }
equals new { Case_StatusId = CS.Case_StatusId } into CS_join
from CS in CS_join.DefaultIfEmpty()
where
AT.CaseID == CaseID
orderby
AT.ModifiedOn descending
select new
{
ID = (int?)AT.ID,
Case_StatusId = CS.Case_StatusId != null ? CS.Case_StatusId : 1, //Case_StatusId comes for row whose FieldName=Status Else No Case_StatusId
AT.CaseID,
AT.RecordType,
AT.ColumnName,
AT.FieldName,
AT.OldValue,
AT.NewValue,
AT.ModifiedBy,
UserName = AT.User != null ? AT.User.UserName : "",
AT.ModifiedOn,
UploadFilename = CS.UploadFilename
}).ToList();

Left outter join linq

How do i change the training events into a left outer join in training events im very basic at linq so excuse my ignorance its not retrieve records that don't have any trainnevent reference attached to it
var q = from need in pamsEntities.EmployeeLearningNeeds
join Employee e in pamsEntities.Employees on need.EmployeeId equals e.emp_no
join tevent in pamsEntities.TrainingEvents on need.TrainingEventId equals tevent.RecordId
where need.EmployeeId == employeeId
where need.TargetDate >= startdate
where need.TargetDate <= enddate
orderby need.TargetDat
It's best to use where in combination with DefaultIfEmpty.
See here: LEFT JOIN in LINQ to entities?
var query2 = (
from users in Repo.T_Benutzer
from mappings in Repo.T_Benutzer_Benutzergruppen.Where(mapping => mapping.BEBG_BE == users.BE_ID).DefaultIfEmpty()
from groups in Repo.T_Benutzergruppen.Where(gruppe => gruppe.ID == mappings.BEBG_BG).DefaultIfEmpty()
//where users.BE_Name.Contains(keyword)
// //|| mappings.BEBG_BE.Equals(666)
//|| mappings.BEBG_BE == 666
//|| groups.Name.Contains(keyword)
select new
{
UserId = users.BE_ID
,UserName = users.BE_User
,UserGroupId = mappings.BEBG_BG
,GroupName = groups.Name
}
);
var xy = (query2).ToList();
Which is equivalent to this select statement:
SELECT
T_Benutzer.BE_User
,T_Benutzer_Benutzergruppen.BEBG_BE
-- etc.
FROM T_Benutzer
LEFT JOIN T_Benutzer_Benutzergruppen
ON T_Benutzer_Benutzergruppen.BEBG_BE = T_Benutzer.BE_ID
LEFT JOIN T_Benutzergruppen
ON T_Benutzergruppen.ID = T_Benutzer_Benutzergruppen.BEBG_BG