Wie treten Sie links in Linq, wenn es mehr als ein Feld in der Join?
-
11-09-2019 - |
Frage
Ich fragte eine Frage früher über warum schließt sich links in Linq nicht definierten Beziehungen verwenden ; Ich habe keine zufriedenstellende Antwort auf Verabredung.
Nun, auf einer parallelen Strecke habe ich akzeptiert, dass ich das join
Schlüsselwort verwenden müssen, als ob es keine Beziehung zwischen meinen Objekten definiert waren, und ich versuche, herauszufinden, wie meine Abfrage in Linq zum Ausdruck bringen. Das Problem ist, es ist ein Konglomerat von links zwischen mehreren Tabellen verknüpft, mit mehreren Feldern beteiligt in der Verknüpfung. Es gibt keine Möglichkeit, dies zu vereinfachen, also hier ist die SQL in all seiner Herrlichkeit nicht maskiert:
select *
from TreatmentPlan tp
join TreatmentPlanDetail tpd on tpd.TreatmentPlanID = tp.ID
join TreatmentAuthorization auth on auth.TreatmentPlanDetailID = tpd.ID
left join PatientServicePrescription rx on tpd.ServiceTypeID = rx.ServiceTypeID
left join PayerServiceTypeRules pstr on auth.PayerID = pstr.PayerID and tpd.ServiceTypeID = pstr.ServiceTypeID and pstr.RequiresPrescription = 1
where tp.PatientID = @PatientID
(FYI, wenn es hilft zu verstehen, was ich versuche zu tun: Ich versuche, wenn es zu identifizieren irgendwelche TreatmentPlanDetail
Aufzeichnungen für diese Patient
wo der bevollmächtigte Payer
für dieses ServiceType
ein Rezept erfordert, aber es gibt auch keine ServicePerscription
Datensatz oder es ist abgelaufen.)
Nun, hier ist, was mein C # Code wie folgt aussieht:
var q = from tp in TreatmentPlans
from tpd in tp.Details
from auth in tpd.Authorizations
join rx in ServicePrescriptions.DefaultIfEmpty() on tpd.ServiceTypeID equals rx.ServiceTypeID
// from pstr in auth.Payer.ServiceTypeRules.DefaultIfEmpty() -- very frustrating that this doesn't work!!
join pstr in LinqUtils.GetTable<PayerServiceTypeRules>().DefaultIfEmpty()
on new { auth.PayerID, tpd.ServiceTypeID, RxReq = (bool)true } equals new { pstr.PayerID, pstr.ServiceTypeID, pstr.RequiresPrescription }
select new { Payer = auth.Payer, Prescription = rx, TreatmentPlanDetail = tpd, Rules = pstr };
Oops, nicht kompilieren! Aus irgendeinem Grund (ich würde eine Erklärung Liebe) Ich nicht, dass die wörtliche boolean innerhalb des Equijoin verwenden können! Gut, ich lasse es aus und auszufiltern die „RequiresPrescription“ stuff später ...
...
join pstr in LinqUtils.GetTable<PayerServiceTypeRules>().DefaultIfEmpty()
on new { auth.PayerID, tpd.ServiceTypeID } equals new { pstr.PayerID, pstr.ServiceTypeID }
...
... und jetzt stellt es - aber wenn ich laufe, bekomme ich einen „Objektverweis nicht festgelegt“ Ausnahme auf dieser Linie. DUH! Natürlich gibt es eine Null in there! Wie sonst soll man einen Vergleich mit einem links ausführen kommen, wenn Sie nicht erlaubt sind, das Objekt auf der rechten Seite zu verweisen, das könnte möglicherweise null sein?
Also, wie soll man nach links trete mit mehreren Feldern?
Lösung
Ich glaube, Sie brauchen das into
Schlüsselwort verwenden und beheben, um die fehlenden Kinder DefaultIfEmpty () nach die Verbindung nicht vor:
...
join pstr in LinqUtils.GetTable<PayerServiceTypeRules>()
on new { auth.PayerID, tpd.ServiceTypeID, bool RequiresPrescription = true }
equals new { pstr.PayerID, pstr.ServiceTypeID, pstr.RequiresPrescription }
into pstrs
from PSTR in pstrs.DefaultIfEmpty()
select new {
Payer = auth.Payer,
Prescription = rx,
TreatmentPlanDetail = tpd,
Rules = PSTR
};
LinqUtils.GetTable<PayerServiceTypeRules>().DefaultIfEmpty()
dreht wahrscheinlich eine Null, weil die Datatable ergab keine Zeilen enthält , so dass Ihre Ausnahme verursacht. Beachten Sie die gesamte Anweisung nach in
hinein ausgeführt wird vor der Auswahl, die nicht die gewünschte Verhalten. Sie möchten die passenden Zeilen oder null, wenn keine passenden Zeilen vorhanden sind.
Für das boolean Problem ist es ein Namensproblem (nichts übereinstimmt „RxReq“ auf der rechten Seite und nichts paßt „RequiresPrescription“ auf der linken Seite). Versuchen Sie die Benennung der true
„RequiresPrescription“, wie ich oben (oder nennen die pstr.RequiresPrescription
über die rechte Seite „RxReq“).