LINQ query with sub-query on LEFT JOIN conditions - c#

I have these queries in SQL and LINQ that were built to retrieve the same data. Unfortunately they are retrieving different amount of records (LINQ returns 1555 values, and SQL returns 1969) and I can't figure out why.
Please help me to find out what I'm missing. Follows the queries:
SQL:
SELECT l.Lease_Detail_ID, l.Lease_ID, l.XRef_Lease_ID, v.Vendor_Name, l.Description, c.County, l.Amount, l.Payment_Due_Date,
l.Lease_Type, l.Location_ID, l.Active, l.Expiration_Date, a.Authorized, p.Payment_Date
FROM tblfLeaseDetail AS l
LEFT JOIN tblvVendor AS v ON l.Vendor_ID = v.Vendor_ID
LEFT JOIN tblvCounty AS c ON l.County_ID = c.County_ID
LEFT JOIN tblfAuthorization AS a ON l.Lease_Detail_ID = a.Lease_Detail_ID
AND a.Authorization_ID = (SELECT TOP 1 Authorization_ID
FROM tblfAuthorization
WHERE Lease_Detail_ID = l.Lease_Detail_ID
ORDER BY Authorized_Date)
LEFT JOIN tblfPayment AS p ON l.Lease_Detail_ID = p.Lease_Detail_ID
AND p.Payment_ID = (SELECT TOP 1 Payment_ID
FROM tblfPayment
WHERE Lease_Detail_ID = l.Lease_Detail_ID
ORDER BY payment_date)
ORDER BY l.Lease_Detail_ID
LINQ: (Edited after a few comments)
var leaseList = (from l in leases.tblfLeaseDetails
join v in leases.tblvVendors on l.Vendor_ID equals v.Vendor_ID into lv
from jlv in lv.DefaultIfEmpty()
join c in leases.tblvCounties on l.County_ID equals c.County_ID into lc
from jlc in lc.DefaultIfEmpty()
join a in leases.tblfAuthorizations on l.Lease_Detail_ID equals a.Lease_Detail_ID into la
from jla in la.DefaultIfEmpty()
where jla.Authorization_ID == (from aj in leases.tblfAuthorizations
where aj.Lease_Detail_ID == l.Lease_Detail_ID
orderby aj.Authorized_Date ascending
select aj.Authorization_ID).FirstOrDefault()
join p in leases.tblfPayments on l.Lease_Detail_ID equals p.Lease_Detail_ID into lp
from jlp in lp.DefaultIfEmpty()
where jlp.Payment_ID == (from pj in leases.tblfPayments
where pj.Lease_Detail_ID == l.Lease_Detail_ID
orderby pj.Payment_Date ascending
select pj.Payment_ID).FirstOrDefault()
select new LeaseViewModel()
{
Lease_Detail_ID = l.Lease_Detail_ID,
Lease_ID = l.Lease_ID,
XRef_Lease_ID = l.XRef_Lease_ID,
Vendor_Name = jlv.Vendor_Name,
Description = l.Description,
County = jlc.County,
Amount = l.Amount,
Payment_Due_Date = l.Payment_Due_Date,
Lease_Type = l.Lease_Type.ToString(),
Location_ID = l.Location_ID,
Active = l.Active,
Expiration_Date = l.Expiration_Date,
Authorized = jla.Authorized,
Payment_Date = jlp.Payment_Date
});
EDIT:
After analyzing the run-time SQL query generated by LINQ statement I found out that it's creating the Authorized sub-query in the wrong place. Here is what it looks like:
SELECT [t0].[Lease_Detail_ID], [t0].[Lease_ID], [t0].[XRef_Lease_ID], [t1].[Vendor_Name] AS [Vendor_Name], [t0].[Description], [t2].[County] AS [County], [t0].[Amount], [t0].[Payment_Due_Date], [t0].[Expiration_Date], [t3].[Authorized] AS [Authorized], CONVERT(NVarChar(1),[t0].[Lease_Type]) AS [Lease_Type], [t0].[Location_ID], CONVERT(Int,[t0].[Active]) AS [Active], [t4].[Payment_Date] AS [Payment_Date]
FROM [dbo].[tblfLeaseDetail] AS [t0]
LEFT OUTER JOIN [dbo].[tblvVendor] AS [t1] ON [t0].[Vendor_ID] = ([t1].[Vendor_ID])
LEFT OUTER JOIN [dbo].[tblvCounty] AS [t2] ON [t0].[County_ID] = ([t2].[County_ID])
LEFT OUTER JOIN [dbo].[tblfAuthorization] AS [t3] ON ([t0].[Lease_Detail_ID]) = [t3].[Lease_Detail_ID]
LEFT OUTER JOIN [dbo].[tblfPayment] AS [t4] ON ([t0].[Lease_Detail_ID]) = [t4].[Lease_Detail_ID]
WHERE ([t4].[Payment_ID] = ((SELECT TOP (1) [t5].[Payment_ID] FROM [dbo].[tblfPayment] AS [t5] WHERE [t5].[Lease_Detail_ID] = ([t0].[Lease_Detail_ID])
ORDER BY [t5].[Payment_Date] )))
AND ([t3].[Authorization_ID] = (( SELECT TOP (1) [t6].[Authorization_ID]
FROM [dbo].[tblfAuthorization] AS [t6]
WHERE [t6].[Lease_Detail_ID] = ([t0].[Lease_Detail_ID])
ORDER BY [t6].[Authorized_Date] )))
The problem is that it only made more confuse, once Payment and Authorized joins have exactly the same structure.

after some research I finally found how to do it. Here is the LINQ query that generates the SQL I was trying to get:
var leaseList = (from l in leases.tblfLeaseDetails
join p in leases.tblfPayments
on l.Lease_Detail_ID equals p.Lease_Detail_ID into lp
from jlp in lp.Where(x => x.Payment_ID == (from pj in leases.tblfPayments
where pj.Lease_Detail_ID == l.Lease_Detail_ID
orderby pj.Payment_Date ascending
select pj.Payment_ID).FirstOrDefault()).DefaultIfEmpty()
join a in leases.tblfAuthorizations on l.Lease_Detail_ID equals a.Lease_Detail_ID into la
from jla in la.Where(x => x.Authorization_ID == (from aj in leases.tblfAuthorizations
where aj.Lease_Detail_ID == l.Lease_Detail_ID
orderby aj.Authorized_Date ascending
select aj.Authorization_ID).FirstOrDefault()).DefaultIfEmpty()
join v in leases.tblvVendors on l.Vendor_ID equals v.Vendor_ID into lv
from jlv in lv.DefaultIfEmpty()
join c in leases.tblvCounties on l.County_ID equals c.County_ID into lc
from jlc in lc.DefaultIfEmpty()
select new LeaseViewModel()
{
Lease_Detail_ID = l.Lease_Detail_ID,
Lease_ID = l.Lease_ID,
XRef_Lease_ID = l.XRef_Lease_ID,
Vendor_Name = jlv.Vendor_Name,
Description = l.Description,
County = jlc.County,
Amount = l.Amount,
Payment_Due_Date = l.Payment_Due_Date,
Lease_Type = l.Lease_Type.ToString(),
Location_ID = l.Location_ID,
Active = l.Active,
Expiration_Date = l.Expiration_Date,
Authorized = jla.Authorized,
Payment_Date = jlp.Payment_Date
});

Related

Selecting max in linq query or rewriting to method chain syntax

I managed to turn this SQL query:
SELECT c.carId, c.Codename, count(c.CarId) as [CarCount],
FROM [DbEfTesting].[dbo].[Cars] c
left join Accessories a on c.CarId = a.CarId
left join CarsPeople cp on cp.CarId = c.CarId
left join People p on cp.PersonId = p.PersonId
group by c.CarId, c.Codename
into a LINQ query:
var x = from c in _context.Cars
join a in _context.Accessories on c.CarId equals a.Car.CarId
join j in _context.CarsPeople on c.CarId equals j.CarId
join p in _context.People on j.PersonId equals p.PersonId
group c by new { c.CarId, c.Codename } into g
select new VMCarAggregate()
{
CarId = g.Key.CarId,
Codename = g.Key.Codename,
CarCount = g.Count()
};
But now I'm lost trying to include a max value e.g the SQL:
SELECT c.carId, c.Codename, count(c.CarId) as [CarCount], max(a.AccessoryId) ...
I googled it and found lots of answers for method syntax. If I were using method chain syntax, I know I could do something like this:
_context.Accessories.Max(a => a.AccessoryId);
but I can't figure out how to do the group by in method chain syntax so either:
How can I convert that query to method syntax?
or
How can I inject a select on the max a.AccessoryId in the LINQ query format?
Try the below code once:
var x = from c in _context.Cars
join a in _context.Accessories equals a.Car.CarId
join j in _context.CarsPeople on c.CarId equals j.CarId
join p in _context.People on j.PersonId equals p.PersonId
group new { c.CarId, c.Codename, a.AccesoryId } by new { c.CarId, c.Codename } into g
select new
{
CarId = g.Key.CarId,
Codename = g.Key.Codename,
CarCount = g.Count(),
MaxAccesory = g.Max(z => z.AccesoryId)
};

linq to sql make simple group by at the end

I have this linq
(from a in Customers
join b in CustomerContacts.Where(p => p.Contact.ContactType.Code == "phone") on a.Id equals b.CustomerId into bb
from b in bb.DefaultIfEmpty()
join e in CustomerContacts.Where(p => p.Contact.ContactType.Code == "email") on a.Id equals e.CustomerId into ee
from e in ee.DefaultIfEmpty()
join f in Bookings.Where(p => p.EntityId == 4) on a.Id equals f.CustomerId into ff
from f in ff.DefaultIfEmpty()
join h in CustomerAddresses on a.Id equals h.CustomerId into hh
from h in hh.DefaultIfEmpty()
where
(b.Contact.Value.Contains("123") || e.Contact.Value.Contains("123"))
&& (a.EntityId == 4 || f != null)
select new {
a.Id,
phone = b.Contact.Value,
email = e.Contact.Value,
count = Vehicles.Where(p => p.CustomerId == a.Id).Count(),
h.Address.State,
h.Address.Suburb
}
)
It translated to sql (mysql)
SELECT `a`.`Id`, `b.Contact`.`Value` AS `phone`, `e.Contact`.`Value` AS `email`, (
SELECT COUNT(*)
FROM `Vehicle` AS `p2`
WHERE `p2`.`CustomerId` = `a`.`Id`
) AS `count`, `h.Address`.`State`, `h.Address`.`Suburb`
FROM `Customer` AS `a`
LEFT JOIN (
SELECT `p`.*
FROM `CustomerContact` AS `p`
INNER JOIN `Contact` AS `p.Contact` ON `p`.`ContactId` = `p.Contact`.`Id`
INNER JOIN `ContactType` AS `p.Contact.ContactType` ON `p.Contact`.`ContactTypeId` = `p.Contact.ContactType`.`Id`
WHERE `p.Contact.ContactType`.`Code` = 'phone'
) AS `t` ON `a`.`Id` = `t`.`CustomerId`
LEFT JOIN `Contact` AS `b.Contact` ON `t`.`ContactId` = `b.Contact`.`Id`
LEFT JOIN (
SELECT `p0`.*
FROM `CustomerContact` AS `p0`
INNER JOIN `Contact` AS `p.Contact0` ON `p0`.`ContactId` = `p.Contact0`.`Id`
INNER JOIN `ContactType` AS `p.Contact.ContactType0` ON `p.Contact0`.`ContactTypeId` = `p.Contact.ContactType0`.`Id`
WHERE `p.Contact.ContactType0`.`Code` = 'email'
) AS `t0` ON `a`.`Id` = `t0`.`CustomerId`
LEFT JOIN `Contact` AS `e.Contact` ON `t0`.`ContactId` = `e.Contact`.`Id`
LEFT JOIN (
SELECT `p1`.*
FROM `Booking` AS `p1`
WHERE `p1`.`EntityId` = 4
) AS `t1` ON `a`.`Id` = `t1`.`CustomerId`
LEFT JOIN `CustomerAddress` AS `h` ON `a`.`Id` = `h`.`CustomerId`
LEFT JOIN `Address` AS `h.Address` ON `h`.`AddressId` = `h.Address`.`Id`
WHERE ((LOCATE('123', `b.Contact`.`Value`) > 0) OR (LOCATE('123', `e.Contact`.`Value`) > 0)) AND ((`a`.`EntityId` = 4) OR `t1`.`Id` IS NOT NULL)
and the result
however it contains duplicated Id, I want to add group by a.Id at the end to remove duplicated Id. Tried with group by but it cannot achieve some thing like this
SELECT `a`.`Id`, `b.Contact`.`Value` AS `phone`, `e.Contact`.`Value` AS `email`, (
SELECT COUNT(*)
FROM `Vehicle` AS `p2`
WHERE `p2`.`CustomerId` = `a`.`Id`
) AS `count`, `h.Address`.`State`, `h.Address`.`Suburb`
FROM `Customer` AS `a`
LEFT JOIN (
SELECT `p`.*
FROM `CustomerContact` AS `p`
INNER JOIN `Contact` AS `p.Contact` ON `p`.`ContactId` = `p.Contact`.`Id`
INNER JOIN `ContactType` AS `p.Contact.ContactType` ON `p.Contact`.`ContactTypeId` = `p.Contact.ContactType`.`Id`
WHERE `p.Contact.ContactType`.`Code` = 'phone'
) AS `t` ON `a`.`Id` = `t`.`CustomerId`
LEFT JOIN `Contact` AS `b.Contact` ON `t`.`ContactId` = `b.Contact`.`Id`
LEFT JOIN (
SELECT `p0`.*
FROM `CustomerContact` AS `p0`
INNER JOIN `Contact` AS `p.Contact0` ON `p0`.`ContactId` = `p.Contact0`.`Id`
INNER JOIN `ContactType` AS `p.Contact.ContactType0` ON `p.Contact0`.`ContactTypeId` = `p.Contact.ContactType0`.`Id`
WHERE `p.Contact.ContactType0`.`Code` = 'email'
) AS `t0` ON `a`.`Id` = `t0`.`CustomerId`
LEFT JOIN `Contact` AS `e.Contact` ON `t0`.`ContactId` = `e.Contact`.`Id`
LEFT JOIN (
SELECT `p1`.*
FROM `Booking` AS `p1`
WHERE `p1`.`EntityId` = 4
) AS `t1` ON `a`.`Id` = `t1`.`CustomerId`
LEFT JOIN `CustomerAddress` AS `h` ON `a`.`Id` = `h`.`CustomerId`
LEFT JOIN `Address` AS `h.Address` ON `h`.`AddressId` = `h.Address`.`Id`
WHERE ((LOCATE('123', `b.Contact`.`Value`) > 0) OR (LOCATE('123', `e.Contact`.`Value`) > 0)) AND ((`a`.`EntityId` = 4) OR `t1`.`Id` IS NOT NULL)
Group by `a`.`Id`
Have you tried something like this?
(from a in Customers
join b in CustomerContacts.Where(p => p.Contact.ContactType.Code == "phone") on a.Id equals b.CustomerId into bb
from b in bb.DefaultIfEmpty()
join e in CustomerContacts.Where(p => p.Contact.ContactType.Code == "email") on a.Id equals e.CustomerId into ee
from e in ee.DefaultIfEmpty()
join f in Bookings.Where(p => p.EntityId == 4) on a.Id equals f.CustomerId into ff
from f in ff.DefaultIfEmpty()
join h in CustomerAddresses on a.Id equals h.CustomerId into hh
from h in hh.DefaultIfEmpty()
where
(b.Contact.Value.Contains("123") || e.Contact.Value.Contains("123"))
&& (a.EntityId == 4 || f != null)
select new {
a.Id,
phone = b.Contact.Value,
email = e.Contact.Value,
count = Vehicles.Where(p => p.CustomerId == a.Id).Count(),
h.Address.State,
h.Address.Suburb
}).GroupBy(i => i.Id).ToList();

WHERE condition with SELECT, MAX statement using LINQ/Lambda

I am trying to convert below SQL query to LINQ/Lambda in C#
SELECT DISTINCT M.InternalID, P.Code
FROM (
dbo.MeasureValue MV
INNER JOIN dbo.Measure M ON MV.MeasureID = M.ID
INNER JOIN dbo.Provider P ON MV.ProviderID = P.ID
)
WHERE MV.ReportingDate = (
SELECT MAX(ReportingDate)
FROM (
SELECT ReportingDate
FROM dbo.MeasureValue
WHERE MeasureID = MV.MeasureID
) MaxReportingDate
);
I have got so far,
(from MV in MeasureValues
join M in Measures on MV.MeasureID equals M.ID
join P in Providers on MV.ProviderID equals P.ID
Where //???
select new //Distinct??
{ M.InternalID, P.Code} )
Could someone please guide me how to use nested WHERE condition as in SQL query and do MAX of nested SELECT and DISTINCT on whole?
As a whole the LINQ/Lamda should output same result as SQL query.
*I am new to SQL and LINQ
Thanks in advance.
Try this one:
var query =
from mv in MeasureValues
join m in Measures on mv.MeasureID equals m.ID
join p in Providers on mv.ProviderID equals p.ID
where mv.ReportingDate ==
(from mv2 in MeasureValues
where mv2.MeasureID == mv.MeasureID
orderby mv2.ReportingDate descending
select mv2.ReportingDate
).FirstOrDefault()
select new { m.InternalID, p.Code };
var distinct =
from q in query
group q by new { q.InternalID, q.Code} into gr
select new
{
InternalID = gr.First().InternalID,
Code = gr.First().Code
};
var result = distinct.ToList();
Another option to find max ReportingDate:
var query =
from mv in MeasureValues
join m in Measures on mv.MeasureID equals m.ID
join p in Providers on mv.ProviderID equals p.ID
where mv.ReportingDate == MeasureValues.Where(x => x.MeasureID == mv.MeasureID).Select(x => x.ReportingDate).Max()
select new { m.InternalID, p.Code };

LINQ left outer join with exclusion

I'm trying to exclude the results of a first query from being included in the results of my second query.
The SQL equivalent is here, where A is my current query, and B is the old query.
I've been trying to use this guide to do the left join, but I can't seem to figure out how it should work in my case. I'm just not understanding how this should work (I can't get the syntax highlighting to be happy).
var emp = from employee in empl
join jc in jce on callout.job_class_code_fk equals jc.job_class_code_fk
join av in ab on employee.employee_id_pk equals av.employee_id_fk
join sh in sho on employee.employee_id_pk equals sh.employee_id_fk into lj
from rnd2 in lj.DefaultIfEmpty()
orderby employee.seniority descending
select new
{
eid = employee.employee_id_pk,
sen = employee.seniority,
nam = employee.employee_name,
pho = employee.phone_number,
lje = sho == null ? sho.employee_id_fk : null //left outer join with exclusion??
};
EDIT:: Based on the suggestions in the comments I've tried both of the following. While I don't have syntax issues any more, neither of the following return ANY results, so there's still something wrong here.
var emp = from employee in empl
join jc in jce on callout.job_class_code_fk equals jc.job_class_code_fk
join av in ab on employee.employee_id_pk equals av.employee_id_fk
join sh in sho on employee.employee_id_pk equals sh.employee_id_fk into lj
from rnd2 in lj.DefaultIfEmpty() where sho == null
orderby employee.seniority descending
select new
{
eid = employee.employee_id_pk,
sen = employee.seniority,
nam = employee.employee_name,
pho = employee.phone_number,
};
var emp = from employee in empl
join jc in jce on callout.job_class_code_fk equals jc.job_class_code_fk
join av in ab on employee.employee_id_pk equals av.employee_id_fk
join sh in sho on employee.employee_id_pk equals sh.employee_id_fk into lj
from rnd2 in lj.DefaultIfEmpty() where rnd2 == null
orderby employee.seniority descending
select new
{
eid = employee.employee_id_pk,
sen = employee.seniority,
nam = employee.employee_name,
pho = employee.phone_number,
};
Okay so (to me anyway) the answer that is the easiest to read and understand ended up being this.
Create two lists, the one I want to exclude, and the master list.
They we run master.Except(exclude) and voila. We've accomplished the effect of a left outer join with exclusion.
Here's the working code. The solutions above could very well have worked, as there was another problem with how the first list was being put together.
var ex = from employee in empl
join sh in sho on employee.employee_id_pk equals sh.employee_id_fk
select new
{
eid = employee.employee_id_pk,
sen = employee.seniority,
nam = employee.employee_name,
pho = employee.phone_number,
};
ex.Distinct();
//get a list of employees who have the enabled orientations and job classifications
var emp = from employee in empl
join jc in jce on employee.employee_id_pk equals jc.employee_id_fk
join av in ab on employee.employee_id_pk equals av.employee_id_fk
orderby employee.seniority descending
select new
{
eid = employee.employee_id_pk,
sen = employee.seniority,
nam = employee.employee_name,
pho = employee.phone_number,
};
emp = emp.Distinct();
emp = emp.Except(ex);

How to use left outer join in LINQ for SQL query?

How can I use left outer join in LINQ for the following SQL query?
SELECT a.EventID, a.PrizeId, b.PrizeName, b.PrizeValue, c.FightID, c.Winnerid, c.WinnerName
FROM tblUserprize a
JOIN tblPrizeDetails b
ON a.PrizeId=b.PrizeId
LEFT OUTER JOIN tblWinnersList c
ON a.EventID=c.EventID AND a.PrizeId=c.PrizeId AND c.FightID = 1534
WHERE a.EventID = 1320
It should look like this:
var userPrize = (
from a in tblUserprize
join b in tblPrizeDetails on a.PrizeId equals b.PrizeId
join c in tblWinnersList on new { a.EventID, a.PrizeId } equals new { c.EventID, c.PrizeId } into joinedTables
from item in joinedTables.DefaultIfEmpty()
where a.EventID == 1320 && item.FightID == 1534
select new
{
a.EventID,
a.PrizeId,
b.PrizeName,
b.PrizeValue,
item.FightID,
item.Winnerid,
item.WinnerName
});

Categories

Resources