Linq - unable to join table due to null value - linq

I am having problem with joining of multiple tables.
PatientID can be null. Whenever patientID is null, it is unable to join and the result will not be added to the list.
Any suggestion on how i can do to join them ?
List<ViewActivityLogViewModel> q = new List<ViewActivityLogViewModel>();
q = (from l in logs
join lc in logCategories on l.logCategoryID equals lc.logCategoryID
join p in patients on l.patientID equals p.patientID
join u in users on l.userIDInit equals u.userID
join ut in usertypes on u.userTypeID equals ut.userTypeID
join u2 in users on l.userIDApproved equals u2.userID
join ut2 in usertypes on u2.userTypeID equals ut2.userTypeID
select new ViewActivityLogViewModel
{
logID = l.logID,
logCategoryName =lc.logCategoryName,
firstName = p.firstName,
userIDInitfirstName = u.firstName,
userIDInituserTypeName = ut.userTypeName,
userIDApprovedfirstName = u2.firstName,
userIDApproveduserTypeName = ut2.userTypeName
}
).OrderBy(x=>x.createDateTime).ToList();
This is the answer i need. I written it in SQL.
SELECT l.logID, lc.logCategoryName,p.firstName, p.lastName, u.firstName, ut.userTypeName, u2.firstName, ut2.userTypeName
FROM log AS l
LEFT JOIN patient AS p ON l.patientID = p.patientID
JOIN logCategory AS lc ON l.logCategoryID = lc.logCategoryID
JOIN user AS u ON l.userIDInit = u.userID
JOIN userType AS ut ON u.userTypeID = ut.userTypeID
JOIN user AS u2 ON l.userIDApproved = u2.userID
JOIN userType AS ut2 ON u2.userTypeID = ut2.userTypeID

You can use GroupJoin to join the patients table and get the data. According to MSDN, GroupJoin in Lambda supports the LEFT JOIN in SQL.
GroupJoin preserves the order of the elements of outer, and for each
element of outer, the order of the matching elements from inner.
GroupJoin has no direct equivalent in
traditional relational database terms. However, this method does
implement a superset of inner joins and left outer joins. Both of
these operations can be written in terms of a grouped join.
So, your query can be written as,
var results =
logs.Join(logCategories, l => l.logCategoryID, lc => lc.logCategoryID, (l, lc) => new { l, lc })
.Join(users, llc => new { userId = llc.l.userIDInit }, u1 => new { userId = u1.userID }, (llc, u1) => new { llc.l, llc.lc, u1 })
.Join(userTypes, llcu1 => llcu1.u1.userTypeID, ut1 => ut1.userTypeID, (llcu1, ut1) => new { llcu1.l, llcu1.lc, llcu1.u1, ut1 })
.Join(users, llcu2 => new { approvedId = llcu2.l.userIDApproved }, u2 => new { approvedId = u2.userID }, (llcu2, u2) => new { llcu2.l, llcu2.lc, llcu2.u1, llcu2.ut1, u2 })
.Join(userTypes, llcu3 => llcu3.u2.userTypeID, ut2 => ut2.userTypeID, (llcu3, ut2) => new { llcu3.l, llcu3.lc, llcu3.u1, llcu3.u2, llcu3.ut1, ut2 })
.GroupJoin(patients, llcu4 => llcu4.l.patientID, p => p.patientID, (llcu4, p) => new { llcu4.l, llcu4.lc, llcu4.u1, llcu4.u2, llcu4.ut1, llcu4.ut2, p })
.SelectMany(x => x.p.DefaultIfEmpty(), (prj, y) =>
{
return new ViewActivityLogViewModel
{
logID = prj.l.logID,
logCategoryName = prj.lc.logCategoryName,
firstName = y != null ? y.firstName : null,
userIDInitfirstName = prj.u1.firstName,
userIDInituserTypeName = prj.ut1.userTypeName,
userIDApprovedfirstName = prj.u2.firstName,
userIDApproveduserTypeName = prj.ut2.userTypeName
};
}).ToList();
C# Fiddle with sample data.

I am not sure why did u
replicated the joins which could be achieved in two joins only
JOIN user AS u ON l.userIDInit = u.userID
JOIN userType AS ut ON u.userTypeID = ut.userTypeID
JOIN user AS u2 ON l.userIDApproved = u2.userID
JOIN userType AS ut2 ON u2.userTypeID = ut2.userTypeID
as
JOIN user AS u ON l.userIDInit = u.userID and l.userIDApproved = u.userID
JOIN userType AS ut ON u.userTypeID = ut.userTypeID
The below query will give u ur desired result
q = (from l in log
join lc in logCategory
on l.logCategoryID equals lc.logCategoryID
join u in user
on new {a1=l.userIDInit,a2=l.userIDApproved} equals
new {a1=u.userID, a2=u.userID}
join ut in userType
on u.userTypeID equals ut.userTypeID
join p in patient
on l.patientID equals p.patientID
into p11
from p1 in p11.DefaultIfEmpty()
select new {l,lc,u,ut,p1})
.Select(x=>new ViewActivityLogViewModel
{
logID = x.l.logID,
logCategoryName =x.lc.logCategoryName,
firstName = x.p1?.firstName,
userIDInitfirstName = x.u.firstName,
userIDInituserTypeName = x.ut.userTypeName,
userIDApprovedfirstName = x.u.firstName,
userIDApproveduserTypeName = x.ut.userTypeName
})
.OrderBy(x=>x.createDateTime).ToList();

You didn't say which PatientId can be null, so to be on the safe side I assume both can be null.
q = (from l in logs
join lc in logCategories.Where(category => category.PatientId != null)
on l.logCategoryID equals lc.logCategoryID
join p in patients where(patient => patien.PatiendId != null)
on l.patientID equals p.patientID
join ...

Related

Change to Left joins

How can I change this Linq query to left joins instead inner joins?
from EH in db.EventsHistory
join AH in db.EventsAttr on EH.TRANSACTIONID equals AH.TRANSACTIONID
join E in db.Events on EH.EVTID equals E.EVTID
group EH by new { EH.TRANSACTIONID, EH.MACGRP, EH.MACID, EH.ORDID, EH.ORDSPLIT, EH.LINID, EH.EVTDATETIME, EH.MATID, EH.PRODID, E.DESC, NUM_ATTR = AH.TRANSACTIONID } into grouped
select new { grouped.Key.TRANSACTIONID, grouped.Key.MACGRP, grouped.Key.MACID, grouped.Key.ORDID, grouped.Key.ORDSPLIT, grouped.Key.LINID, grouped.Key.EVTDATETIME, grouped.Key.MATID, grouped.Key.PRODID, grouped.Key.DESC, NUM_ATTR = grouped.Count() };
In Linq LEFT JOIN is created by using group join with method DefaultIfEmpty. The basic construction looks like this using query syntax:
var query = from c in db.Customers
join o in db.Orders on c.Id equals o.CustomerId into g
from o in g.DefaultIfEmpty()
select new
{
Customer = c,
Order = o
};
Example with method syntax:
var query = db.Customers
.GroupJoin(db.Orders, c => c.Id, o => o.CustomerId, (c, og) => new
{
Customer = c,
Order = og.DefaultIfEmpty()
});
So your query should look like this:
var query = from eh in db.EventsHistory
join ah in db.EventsAttr on eh.TransactionId equals ah.TransactionId into g
join e in db.Events on eh.EvtId equals e.EvtId into g2
from ah in g.DefaultIfEmpty()
from e in g2.DefaultIfEmpty()
group eh by new { ... } into grouped
select new { ... }

LINQ Multiple table left join, distinct count not giving proper result

I am sql query us producing correct result, but when i'm doing the same in LINQ. Output is incorrect. Please let me know where my making mistake.
Following linq query that i created.
LINQ Query:
List<UserModel> Model = (from users in db.UserM
join ct in db.CustT on users.UserId equals ct.UserID into group1
from g1 in group1.DefaultIfEmpty()
join ti in db.TestIn on g1.TestId equals ti.TestID into group2
from g2 in group2.DefaultIfEmpty()
where (users.CustomerId==CustomerId) && (users.RoleId == 4) && (users.Status == 1)
group new
{
g2.TestInvitationID,
g2.TestID,
}
by new
{
users.FirstName,
users.CreatedOn,
users.Email,
users.UserId
} into group4
select new UserModel
{
Name = group4.Key.FirstName,
CreatedOn = group4.Key.CreatedOn,
EmailId = group4.Key.Email,
UserId = group4.Key.UserId,
NoOfTestTaken = group4.Select(x=>x.TestID).Distinct().Count(),
NoOfInvitationsSent = group4.Count(x => x.TestInvitationID != 0)
}).ToList();
SQL Query:
SELECT IsNull(COUNT(distinct TS.TestId),0) AS NoOfTests,
IsNull(COUNT(TS.TestInvitationID),0) AS NoOfInvitations,
UM.Email,
UM.UserId,
UM.FirstName,
UM.CreatedOn
FROM UserM as UM
left JOIN CustT AS CT
ON UM.UserId=CT.UserId
left JOIN TestIn AS TS
ON TS.TestId = CT.TestId
WHERE UM.CustomerId=41
AND UM.RoleId=4
and UM.[Status]=1
GROUP BY UM.UserId, UM.Email, UM.FirstName, UM.CreatedOn
Tables:
"UserM" - columns: UserId, Email, FirstName, CreatedOn
"CustT" - columns: TestId, UserId,
"TestIn" - columns: TestInvitationId, TestId
The difference between SQL COUNT(expr) and LINQ Count is that the former excludes NULL values, which produces a difference when used on right side of a left outer join with no matching records (SQL will produce 0 while LINQ 1). The closest LINQ equivalent is Count(expr != null).
So the direct translation of your SQL query would be like this (note that the generated SQL query could and most likely will be different):
(A side note: When converting SQL query to LINQ, it's good to use the same aliases to make it easier to see the mappings)
var query =
from um in db.UserMasters
join ct in db.CustTests on um.UserId equals ct.UserID
into ctGroup from ct in ctGroup.DefaultIfEmpty() // left outer join
join ts in db.TestInvitaions on ct.TestId equals ts.TestID
into tsGroup from ts in tsGroup.DefaultIfEmpty() // left outer join
where um.CustomerId == UserSession.CustomerId
&& um.RoleId == 4
&& um.Status == 1
group ts by new { um.UserId, um.Email, um.FirstName, um.CreatedOn } into g
select new UserModel
{
Name = g.Key.FirstName,
CreatedOn = g.Key.CreatedOn,
EmailId = g.Key.Email,
UserId = g.Key.UserId,
NoOfTestTaken = g.Where(ts => ts != null).Select(ts => ts.TestID).Distinct().Count(),
NoOfInvitationsSent = g.Count(ts => ts != null)
};
var result = query.ToList();
I suspect that the following row is the problem because is not the same like in your sql:
Linq:
NoOfInvitationsSent = group4.Count(x => x.TestInvitationID != 0)
SQL:
IsNull(COUNT(TS.TestInvitationID),0) AS NoOfInvitations
Due to counting items from a left join Linq should be instead:
NoOfInvitationsSent = group4.Where(i => i != null).Count()
To put it all together, with a bit of better formatting:
var model = (from users in db.UserMasters
join ct in db.CustTests on users.UserId equals ct.UserID into group1
from ct in group1.DefaultIfEmpty()
join ti in db.TestInvitaions on ct.TestId equals ti.TestID into group2
from ct in group2.DefaultIfEmpty()
where users.CustomerId == UserSession.CustomerId &&
users.RoleId == 4 &&
users.Status == 1
group new { ct.TestInvitationID, ct.TestID }
by new
{
users.FirstName,
users.CreatedOn,
users.Email,
users.UserId
} into grouping
select new UserModel
{
Name = grouping.Key.FirstName,
CreatedOn = grouping.Key.CreatedOn,
EmailId = grouping.Key.Email,
UserId = grouping.Key.UserId,
NoOfTestTaken = grouping.Where(i => i != null).Select(x => x.TestID).Distinct().Count(),
NoOfInvitationsSent = grouping.Where(i => i != null).Count()
}).ToList();

Invalid Expression term Where

I have following LINQ statement:
from o in Orders
join od in OrderDetails on o.OrderNumber equals od.OrderNumber
join r in RMAs on o.OrderNumber equals r.OrderNumber
join rd in RMADetails on r.RMAnumber equals rd.RMAnumber
from i in Inventory
where( a => ( od.SKU == a.LocalSKU)).DefaultIfEmpty()//error is here
where (r.Status != "Pending" && od.Adjustment == false)
select new
{
r.Status,
o.Name,
o.Company,
o.Address,
o.Address2,
o.City,
o.State,
o.Country,
o.Email,
o.Zip,
o.Phone,
o.ShipName,
o.ShipCompany,
o.ShipAddress,
o.ShipAddress2,
o.ShipCity,
o.ShipCountry,
o.ShipState,
o.ShipPhone,
o.ShipZip,
o.OrderNumber,
o.ShippingTotal,
OrderDate = o.OrderDate,
SerialNumbers = rd.SerialNumbers ?? "",
o.SourceOrderID
}
It's giving Invalid Where term. What I want to use LEFT OUTER JOIN having SQL Equivalent left join Inventory i on od.SKU = i.LocalSKU
Try this:
var qry = from o in Orders
join od in OrderDetails.Where(od=>od.Adjustment == false) on o.OrderNumber equals od.OrderNumber
join i in Inventory on i.LocalSKU equals od.SKU into grp
from g in grp.DefaultIfEmpty()
join r in RMAs.Where(r=>r != 'Pending') on o.OrderNumber equals r.OrderNumber
join rd in RMADetails on r.RMAnumber equals rd.RMAnumber
select new
{
//set of columns here
};

linq to entities left outer join

select SF.FOLDER_NAME,SF.CREATED_DATE,COUNT(st.FOLDER_ID)
from SURVEY_FOLDER SF with (nolock) left outer join SURVEY_TEMPLATE ST with (nolock)
on SF.FOLDER_ID=ST.FOLDER_ID
group by SF.FOLDER_NAME,SF.CREATED_DATE
I need this query in Linq :
I have tried this query,but unable to group by.
My Linq Query :
var data = (from xx in VDC.SURVEY_FOLDER
join yy in VDC.SURVEY_TEMPLATE
on xx.FOLDER_ID equals yy.FOLDER_ID into g
from grt in g.DefaultIfEmpty()
select
new
{
xx.FOLDER_NAME,
xx.CREATED_DATE,
count = g.Count()
}).ToList();
I got the Answer :
var data5 = (from SF in VDC.SURVEY_FOLDER
join ST in VDC.SURVEY_TEMPLATE on new { FOLDER_ID = SF.FOLDER_ID } equals new { FOLDER_ID = (Int64)ST.FOLDER_ID } into ST_join
from ST in ST_join.DefaultIfEmpty()
group new { SF, ST } by new
{
SF.FOLDER_NAME,
SF.CREATED_DATE
} into g
select new
{
g.Key.FOLDER_NAME,
CREATED_DATE = (DateTime?)g.Key.CREATED_DATE,
Column1 = (Int64?)g.Count(p => p.ST.FOLDER_ID != null)
}).ToList();

Multiple conditions with Joins in Linq

For the below code it gives the error
type reference failed in the call to Join
how can to fix this
var unp = from v in context.student.Include("subjects").Include("marks")
join n in context.AllStudents
on v.StudentDetails.student_Id equals n.Id
join ss in context.StudentHistory
on v.StBacklogs_Id equals ss.Id
join userName in context.Users
on v.CreatedBy_Id equals userName.Id
join externalId in context.Books
on new { ss.BookNumber, ss.Id } equals new { externalId.BookNumber, externalId.Id }
select new { v, n, ss, userName,externalId };

Resources