I am trying to get my head around how to generate the equivalent of this LEFT JOIN in Linq.
It contains a subquery which gets the lowest service_id for the person in that row being joined, and then also restricts on service_code = "N" in both the subquery and the join). I just cant seem to get it to work in Linq.
SQL:-
LEFT OUTER JOIN SERVICE ON person.id_person = SERVICE.id_person
AND SERVICE.id_service = (SELECT MIN(id_service) FROM SERVICE WHERE id_person = person.id_person AND service_code = 'N')
AND SERVICE.service_code = 'N'
NB: I know how to do the left join correctly (DefaultIfEmpty() etc). Its the subquery that is the problem. How do I squeeze that subquery into the .Where clause in Linq?
This query should give you desired result and should be more performant. Also it shows how to express LEFT JOIN in alternative way.
var query =
from person in ctx.Person
from service in ctx.Service
.Where(service => service.service_code == 'N')
.Where(service => service.id_person = person.id_person)
.OrderBy(service => service.id_service)
.Take(1)
.DefaultIfEmpty()
select new
{
person,
service
};
Related
Using a SQL query within Microsoft SQL Server, I am able to get my desired results. Now I'm trying to utilize this query in my project via LINQ.
My SQL query is
SELECT distinct DeviceId, max (Head), max(Shoulder), max(Chest)
FROM EventUserOverPressure eop
JOIN UserEventInfo uei on uei.UserEventInfo_Id = eop.UserEventInfo_Id
JOIN BlastRecord br ON br.BlastRecord_Id = uei.BlastRecord_Id
JOIN WeaponsFiringLog wfl ON wfl.BlastRecord_Id = br.BlastRecord_Id
JOIN WeaponsFired wf ON wf.Blast_WFL_Id = wfl.Blast_WFL_Id
WHERE br.BlastRecord_Id = 1599
group BY DeviceId
Thus far, my LINQ query is
var myOverPressures = (from eop in db.EventUserOverPressures
join uei in ueiList on eop.UserEventInfo_Id equals uei.UserEventInfo_Id
join br in blastRecords on uei.BlastRecord_Id equals br
join wfl in weaponFiringLogss on uei.BlastRecord_Id equals wfl.BlastRecord_Id
join wf in weaponsFired on wfl.Blast_WFL_Id equals wf.Blast_WFL_Id
where (eop.Chest > 0 || eop.Head > 0 || eop.Shoulder > 0)
select new { eop.DeviceDataId, eop.Head, eop.Shoulder, eop.Chest }).Distinct().ToList();
I know the BlastRecord_Id is set to 1599 and it's a variable in LINQ. That's intentional. I was trying to figure out my query in SQL, so I focused on specific record. In LINQ it needs to work for all BlastRecord_Id's. Using LINQ, I'm able to group by DeviceDataId on the next, outside of the initial query.
My goal is to group by DeviceDataId as part of this query, and get the max values for Head Shoulder and Chest - like I did in the SQL query. If it matters, my end goal is sort my results. I know my SQL query results give me what I need in order to sort how I want. I've spent an embarrassing amount of time trying to figure this out. Any help is greatly appreciated.
Try:
var myOverPressures = (
from eop in db.EventUserOverPressures
join uei in ueiList on eop.UserEventInfo_Id equals uei.UserEventInfo_Id
join br in blastRecords on uei.BlastRecord_Id equals br.BlastRecord_Id
join wfl in weaponFiringLogss on uei.BlastRecord_Id equals wfl.BlastRecord_Id
join wf in weaponsFired on wfl.Blast_WFL_Id equals wf.Blast_WFL_Id
where (eop.Chest > 0 || eop.Head > 0 || eop.Shoulder > 0)
select new { eop.DeviceDataId, eop.Head, eop.Shoulder, eop.Chest }
)
.GroupBy(r => r.DeviceDataId)
.Select(g => new {
DeviceDataId = g.Key,
maxHead = g.Max(r => r.Head),
maxShoulder = g.Max(r => r.Shoulder),
maxChest = g.Max(r => r.Chest)
})
.ToList();
The .GroupBy() maps the data to a collection of groups, each of which has a key and a collection of group member objects. The .Select() then extracts the key and calculates the max of the Head/Shoulder/Chest values within each group.
I removed the .Distinct(), as I believe it is unnecesary due to the fact that each group key (DeviceDataId) should already be distinct.
As a side note: I noticed that the join structure of your query has what appears to be two independent one-to-many join relationships:
BlastRecord
+--> UserEventInfo --> EventUserOverPressure
+--> WeaponsFiringLog --> WeaponsFired
This may lead to the results being the cartesian product of the two join paths, yielding duplicate data. This could be a problem if you were counting of summing the effects, but if max() is the only aggregation used, I do not believe the results are affected.
I believe the grouping and aggregation may also be done in the LINQ query syntax. Something like:
var myOverPressures = (
...
group eop by eop.DeviceDataId into g
select new {
DeviceDataId = g.Key,
maxHead = g.Max(r => r.Head),
maxShoulder = g.Max(r => r.Shoulder),
maxChest = g.Max(r => r.Chest)
}
)
.ToList();
(I am not 100% sure I have this right. If someone spots an error and comments, I will correct the above.)
Try this one
var query = (from eop in db.EventUserOverPressure
join uei in db.UserEventInfo on eop.UserEventInfo_Id equals uei.UserEventInfo_Id
join br in db.BlastRecord on uei.BlastRecord_Id equals br.BlastRecord_Id
join wfl in db.WeaponsFiringLog on br.BlastRecord_Id equals wfl.BlastRecord_Id
join wf in db.WeaponsFired on wfl.Blast_WFL_Id equals wf.Blast_WFL_Id
where br.BlastRecord_Id == 1599
group eop by eop.DeviceId into g
select new
{
DeviceId = g.Key,
Head = g.Max(x => x.Head),
Shoulder = g.Max(x => x.Shoulder),
Chest = g.Max(x => x.Chest)
});
I have a SQL query which includes a left join and a group by- so far so good- my trouble arises from one of the join conditions not being a straight "equals to" and I'm lost where to go with LINQ.
I know multiple join conditions usually involves creating a couple of anonymous objects and comparing them, but when I add an "equal to" and "a greater" than into the mix, I've no idea how that applies.
Here's what I'd like the query to look like if I had invented LINQ, but I know the "and" in my join condition is invalid;
var query =
from csp in db.ChatSessionPersons
join cm in db.ChatMessages on
csp.ChatSessionId equals cm.ChatSessionId
and cm.Id > csp.LastReadChatMessageId
// (i know these should be the other way round,
// but for readability I present them like this!)
into j1
from j2 in j1.DefaultIfEmpty()
group j2 by csp.ChatSessionId into grouped
select new {
ChatSessionId = grouped.Key,
UnreadCount = grouped.Count(t => t.Id != null)};
Any ideas anyone?
You can convert the non-equality condition to a lambda Where on the group join result.
var query = from csp in db.ChatSessionPersons
join cm in db.ChatMessages on csp.ChatSessionId equals cm.ChatSessionId into cmj
select new {
ChatSessionId = csp.ChatSessionId,
UnreadCount = cmj.Where(cm => cm.Id > csp.LastReadChatMessageId).Count()
};
NOTE: I modified the query a bit to remove the group by which isn't needed if you are using a group join that has already grouped the matching results, and to remove the left join DefaultIfEmpty which also isn't needed when processing a group join with something like Count, unless you wanted to return an UnreadCount of 1 when there are no matches, in which case you should put DefaultIfEmpty() before Count().
Of course, you could use query comprehension in the sub-query:
var query = from csp in db.ChatSessionPersons
join cm in db.ChatMessages on csp.ChatSessionId equals cm.ChatSessionId into cmj
select new {
ChatSessionId = csp.ChatSessionId,
UnreadCount = (from cm in cmj where cm.Id > csp.LastReadChatMessageId select cm).Count()
};
I am struggling with trying to write a LINQ statement in LINQ or method syntax, based on the following SQL.
SELECT vr.*
FROM VisualReport vr
JOIN VisualReportRoleList vrl ON vr.VisualReportSK = vrl.VisualReportSK
JOIN Role r ON vrl.RoleSK = r.RoleID
JOIN UserRoleList url ON r.RoleID = url.RoleID
JOIN Users u ON url.UserID = url.UserID
WHERE u.ID = 1
I have tried many things, but without luck. I was going to post some of it here, but it just made this post really messy to read.
Can anyone here help me with this?
Join pattern works like this
Param 1. is the list to join on,
Param 2. key on the left (what your calling join on),
Param 3. key on the right (what your joining to),
Param 4. is the results selector how you want to select the results.
db.VisualReposts.Join(db.VisualRepostRoleLists,
vr => vr.VisualReportSK,
vrl => vrl.VisualReportSK
(vr, vrl) => new { vr, vrl}).Join(db.Roles,
vrj => vrj.vrl.RoleSK,
r => r.RoleID,
vrj, r => new {vr = vrj.vr,
vrl = vrj.vrl,
role = r} )
//follow the same patter for the rest of the joins.
// Also add your where clause, it might be a better idea to start
//from the users table so you can filter first
But if everything is properly foreign keyed, you don't need to do a join you can just access the ICollections. If you can or have them foreign keyed you can access them like this
var user = db.Users.Where(u => u.id == 1);
//everything should have an icollection now so you can access via
//user.UserRoleList.Roles ect or what ever you need
A simple one to one conversion. LinqPad should convert this to equivalent of your query.
var result = (from vr in VisualReport
join vrl in VisualReportRoleList on vr.VisualReportSK equals vrl.VisualReportSK
join r in Role on vrl.RoleSK equals r.RoleID
join url in UserRoleList on vrl.RoleSK equals url.RoleID
join u in Users on url.UserID equals u.UserID
where u.ID == 1
select vr).ToList();
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.
I'm using the following query and am having trouble figuring out how to add a join into it:
var chi = Lnq.attlnks.Where(a => a.ownerid == emSysid)
.Select(c => new { sysid });
How can I join this to the "attach" table (ON attlnks.sysid = attach.sysid) and select "name" where sysid is the row id?
For joins in Linq the query expression form is typically more readable than lambda syntax - I believe this is what you are asking for:
var chi = from t in Lnq.attach
join a in Lnq.attlnks
on t.sysid equals a.sysid
where a.ownerid == emSysid
select t.name;
If there is only a single entry that should match at most, you can chain a FirstOrDefault() in this case (or other alternatives like SingleOrDefault, Single, First etc.):
var chi = (from t in Lnq.attach
join a in Lnq.attlnks
on t.sysid equals a.sysid
where a.ownerid == emSysid
select t.name).FirstOrDefault();
If I understood your problem, this should work fine:
var query = from a in attlinks
join aa in attach on a.sysid equals aa.sysid into a2
where a2.sysid == a2.ownerid
select a2.Name;