I have looked around and found a few posts on adding a second condition to a JOIN clause but they are always instances of having one column link to another but in my instance I need to just have a column equal a certain value. The RAW SQL I am trying to imitate is:
LEFT OUTER JOIN dbo.TimeCardHeader AS tch2 on tch1.EmployeeID = tch2.EmployeeID && tch2.WeekEndingDate = #PayPeriod
As you can see my second join condition is to match a column value from the table to a variable. I have tried the following LINQ queires but they all fail.
join leftth2 in db.TimeCardHeaders on th1.EmployeeID equals leftth2.EmployeeID AND leftth2.WeekEndingDate == PayPeriod into leftjointh2
join leftth2 in db.TimeCardHeaders on th1.EmployeeID equals leftth2.EmployeeID && leftth2.WeekEndingDate == PayPeriod into leftjointh2
join leftth2 in db.TimeCardHeaders on new
{
employeeID = th1.EmployeeID,
weekEndingDate = leftth2.WeekEndingDate
} equals new
{
employeeID = leftth2.EmployeeID,
weekEndingDate = PayPeriod
}
The first two fail saying AND and && are not valid, the last fails saying leftth2 is not in the scope of the left side.
What is the proper way of doing this?
The condition
tch2.WeekEndingDate = #PayPeriod
doesn't feel like part of the join to me - it's not comparing data in two different rows. It feels like it should be part of what you're joining on, leading to:
join leftth2 in db.TimeCardHeaders.Where(p => p.WeekEndingDate == PayPeriod)
on th1.EmployeeID equals leftth2.EmployeeID into leftjointh2
Related
I'm learning Entity Framework and attempting to convert an existing SQL query to a LINQ query, but struggling to convert it.
SELECT taskItems.Description,taskItemResponses.IsCompleted,TaskItemResponses.userId,TaskItemResponses.Notes
FROM TaskLists
LEFT JOIN TaskItems ON TaskLists.TaskListId = TaskItems.TaskListId
LEFT JOIN TaskItemResponses ON TaskItemResponses.TaskItemId = TaskItems.TaskItemId
AND TaskItemResponses.UserId = '1'
This works fine for me, it brings back the following data, always showing the list of Tasks, and if a user has responded to any of them, if they've completed it and what notes they've added.
Description IsCompleted userId Notes
Task A NULL NULL NULL
Task B NULL NULL NULL
Task C NULL NULL NULL
Task D 1 1 I've done this now.
Task E NULL NULL NULL
But when I'm trying to convert this to a LINQ query within C# I can't figure out the syntax, so far i've got
var query = from t in DbContext.TaskList
join ti in DbContext.TaskItem on t.TaskListId equals ti.TaskListId
join tr in DbContext.TaskItemResponse on ti.TaskItemId equals tr.TaskItemId into trj
from x in trj.DefaultIfEmpty()
where x.UserId == userId
select t;
But this isn't filtering for a particular UserId, and instead returns
Description IsCompleted userId Notes
Task A 0 2 Great
Task B 1 2 Okay
Task C 1 3 Nope
Task D 1 1 I've done this now.
Task E 0 5 Ok.
See that. May be you need ome minor changes.
var query = from t in DbContext.TaskList
join ti in DbContext.TaskItem on t.TaskListId equals ti.TaskListId
join tr in DbContext.TaskItemResponse on ti.TaskItemId equals tr.TaskItemId
where(tr.UserId == '1')
select new tempObjList
{
Description = taskItems.Description,
IsCompleted = taskItemResponses.IsCompleted,
userId = TaskItemResponses.userId,
Notes = TaskItemResponses.Notes
};
make "tempObjList" model class.
The correct way to convert SQL LEFT JOIN with right side filter to LINQ is to apply the right side filter before the join operator.
Here is the LINQ equivalent of your SQL query (of course you can correct the field names/types if needed):
var query =
from t in DbContext.TaskList
join ti in DbContext.TaskItem on t.TaskListId equals ti.TaskListId
into tij from ti in tij.DefaultIfEmpty() // left join
join tr in DbContext.TaskItemResponse.Where(x => x.UserId == userId) // filter
on ti.TaskItemId equals tr.TaskItemId
into trj from tr in trj.DefaultIfEmpty() // left join
select new
{
ti.Description,
IsCompleted = (bool?)tr.IsCompleted,
userId = (int?)tr.userId,
tr.Notes
};
In your EF code, the first join is an INNER join and your second one is a LEFT OUTER join
Have a look at these:
First Option
Second Option
Hope these could save you some time.
I currently have some stored procedures in T-SQL that I would like to translate to LINQ-To-Entities for greater maintainability. However, no matter how I seem to construct the LINQ query, when I inspect the generated code, it's an abhorrent terribly-performing monstrosity. I've investigated into various combinations of "let" clauses, joins, shifting around the "where" clause to both inside and out of the anonymous type selection, or even using the extension ".Where<>()" method piecemeal in the other indiciations themselves, and nothing seems to generate code anywhere as close to what I would expect or need.
The difficulties seem threefold:
The joins that I need to do are on combinations of booleans, whereas LINQ-To-Entities seems to only have join functionality for equijoins. How can I translate these joins?
I need to join on the same table multiple different times with different join/where clauses, so that I can select a different value for each record. How do I accomplish this in LINQ-To-Entities?
How do I prevent my joins on entity collections become nested messes?
The T-SQL query I'm attempting to translate is this (where the hardcoded numbers are specific hardcoded types):
SELECT Transport.*,
[Address].Street1,
Carrier1Insurance.InsuranceNumber,
Carrier2Insurance.InsuranceNumber,
Carrier3Insurance.InsuranceNumber
FROM Transport
INNER JOIN Appoint ON Transport.AppointKEY = Appoint.AppointKEY
INNER JOIN Patient ON Appoint.PatientKEY = Patient.PatientKEY
LEFT OUTER JOIN [Address] ON [Address].AddressFKEY = Patient.PatientKEY AND [Address].AddressTypeByTableKEY = 1
LEFT OUTER JOIN PatientInsurance Carrier1Insurance ON Carrier1Insurance.PatientKEY = Patient.PatientKEY AND Carrier1Insurance.CarrierKEY = 7
LEFT OUTER JOIN PatientInsurance Carrier2Insurance ON Carrier2Insurance.PatientKEY = Patient.PatientKEY AND Carrier2Insurance.CarrierKEY = 8
LEFT OUTER JOIN PatientInsurance Carrier3Insurance ON Carrier3Insurance.PatientKEY = Patient.PatientKEY AND (Carrier3Insurance.CarrierKEY <> 7 AND Carrier3Insurance.CarrierKEY = 8)
WHERE (Transport.TransportDate >= '07-01-2013' AND Transport.TransportDate <= '07-31-2013')
AND EXISTS (SELECT TOP 1 *
FROM Remit
WHERE Remit.CarrierKEY = 8
AND Remit.AppointKEY = Transport.AppointKEY
AND Remit.PaidAmt > 0)
And the latest in many, many attempts at LINQ is this:
var medicareTransportList = from transportItem in ClientEDM.Transports
join patientAddress in ClientEDM.Addresses on transportItem.Appoint.PatientKEY equals patientAddress.AddressFKEY
join carrier1Insurance in ClientEDM.PatientInsurances on transportItem.Appoint.PatientKEY equals carrier1Insurance.PatientKEY
join carrier2Insurance in ClientEDM.PatientInsurances on transportItem.Appoint.PatientKEY equals carrier2Insurance.PatientKEY
join otherInsurance in ClientEDM.PatientInsurances on transportItem.Appoint.PatientKEY equals otherInsurance.PatientKEY
where (transportItem.TransportDate > fromDate ** transportItem.TransportDate <= toDate) && transportItem.Appoint.Remits.Any(remit => remit.CarrierKEY == 0 && remit.PaidAmt > 0.00M) &&
(carrier1Insurance.CarrierKEY == 7) &&
(carrier2Insurance.CarrierKEY == 8 ) &&
(otherInsurance.CarrierKEY != 7 &&
otherInsurance.CarrierKEY != 8 ) &&
(patientAddress.AddressTypeByTableKEY == 1)
select new
{
transport = transportItem,
patient = patientAddress,
medicare = medicareInsurance,
medicaid = medicaidInsurance,
other = otherInsurance
};
The LINQ .Join() operator is equivalent to the INNER JOIN SQL operator.
For any other case, use the .GroupJoin() operator.
But do you really need to use join? In many case, using LINQ, SQL JOIN (inner or outer) can be expressed using navigation properties between entities.
Please explains your conceptual data model for a precise answer.
How can I join two different tables based on a condition?
I have my query as under:
var myquery = from p in db.tbl1
join q in db.tbl2 on p.field1 equals q.field1
join r in db.tbl3 on q.field2 equals r.field2
Till here everything is fine, now I want to add 1 more join to a table but it should be based on a condition like:
if(q.field3 == 1)
join s in db.tbl4 on q.field4 equals s.field4
else if(q.field3 == 2)
join s in db.tbl5 on ....
So basically I want to join to different tables based on the value of q.field3.
You're not going to be able to conditionally join based on the value of a single row. The idea of joining is that you're joining based off of all of the rows. Conditionally determining what/how to join based on some value outside of the query would make sense.
What you can do is do both joins unconditionally, but choose which result to use conditionally for each row. Obviously this will only work if the tables are of the same type, or if you first project s1 and s2 into a common type (using let)
var myquery = from p in db.tbl1
join q in db.tbl2 on p.field1 equals q.field1
join r in db.tbl3 on q.field2 equals r.field2
join s1 in db.tbl4 on q.field4 equals s1.field4
join s2 in db.tbl5 on q.field5 equals s2.field5
let s = q.field3 == 1 ? s1 :
q.field3 == 2 ? s2 : null
This should be able to be translated by the query provider into a CASE statement.
I'm quite new to entity framework and I'm trying to use the join clause on two entities as follows.
var alertlist = from elogAlert in yangkeeDBEntity.Yang_Kee_Logistics_Pte_Ltd_ELog_Tablet_Alert
where elogAlert.No_ != null
join elogAlertDetail in yangkeeDBEntity. Yang_Kee_Logistics_Pte_Ltd_ELog_Tablet_Alert_Details
on elogAlert.No_ == elogAlertDetail.AlertID
where elogalertdetail.employee_id == driverid
select new
{
elogalertdetail.employee_id,
elogalertdetail.alert_id,
elogalertdetail.no_,
elogalertdetail.status,
elogalertdetail.created_by,
elogalertdetail.date_created,
};
Hi from the above code I'm getting two errors saying
'Error 1 The name 'elogAlertDetail' is not in scope on the left side of 'equals'. Consider swapping the expressions on either side of 'equals'.' and 'linq joint type inference failed to call 'join' error '
Currently the two tables does not have any data. Ill be happy if anyone can help me with this situation
you cant use == when joining with Linq. You need to use equals.
Note that it is not the method .Equals(..) but the keyword
from elogAlert in yangkeeDBEntity.Yang_Kee_Logistics_Pte_Ltd_ELog_Tablet_Alert
join elogAlertDetail in yangkeeDBEntity.Yang_Kee_Logistics_Pte_Ltd_ELog_Tablet_Alert_Details
on elogAlert.No_ equals elogAlertDetail.AlertID //this line has equals instead of ==
where elogAlert.No_ != null
where elogalertdetail.employee_id == driverid
select new
{
elogalertdetail.employee_id,
elogalertdetail.alert_id,
elogalertdetail.no_,
elogalertdetail.status,
elogalertdetail.created_by,
elogalertdetail.date_created,
};
Look at the documentaion on Linq join
The error you have relates to the order of arguments around the equals operand on join.
The joined table MUST be the RHS of the equals, and the LHS must be in the row you are joining to.
In this instance yangkeeDBEntity is not in the elogAlert row
CF the example in MSDN
from c in categories
join p in products on c equals p.Category into ps
from p in ps
select new { Category = c, p.ProductName };
c is in the row you are joining from, p.category is on the table you are joining to
in addition you also need to use the word equals not == as mentioned above
public IQueryable<RecentlyCreatedAssetViewModel> getRecentlyCreatedAssetsByCompanyID(int companyID)
{
return (from a in db.Assets
join ab in db.AssetBundles on a.AssetID equals ab.AssetID
join b in db.Bundles on ab.BundleID equals b.BundleID
where a.CompanyID == companyID && a.AssetTypeID == 11 && a.IsActive == true && a.ShowInResults == true
orderby a.CreateDate descending
select new RecentlyCreatedAssetViewModel { AssetID = a.AssetID, AssetName = a.AssetName, AssetTypeID = a.AssetTypeID, BundleIcon = b.BundleIcon, BundleName = b.BundleName }).Take(10);
}
It turns out that I want to also get back some db.Assets that do not have relations in db.AssetBundles, however I am not sure how to do this, I want to put empty space (blank strings) in the place of the Bundle fields of the RecentlyCreatedAssetViewModel when there is no relation. This query will not return an Asset that has no relation in the joins though, how can I change this so that it will give them back just putting empty strings in the missing data?
Here's an article about doing LEFT JOINs in Linq-to-sql; Essentially what you are looking for is the DefaultIfEmpty() extension.
Use a LEFT JOIN in your query to get the job done.
More information can be found at W3Schools.
What you need is to perform a left outer join, check out the reference on the join clause in MSDN, and scroll down to the section titled 'Left Outer Join'