¿Cómo se inscribe izquierda en LINQ si hay más de un campo en la unión?
-
11-09-2019 - |
Pregunta
he hecho una pregunta anterior sobre qué une a izquierda en LINQ no pueden utilizar relaciones definidas ; hasta la fecha no tengo una respuesta satisfactoria.
Ahora, en una vía paralela, he aceptado que tengo que utilizar la palabra clave join
como si no hubiera ninguna relación definida entre mis objetos, y yo estoy tratando de encontrar la manera de expresar mi consulta en LINQ. El problema es que se trata de un conglomerado de izquierda se une entre varias tablas, con múltiples campos implicados en la unión. No hay manera de simplificar esto, así que aquí está el SQL en todo su esplendor desenmascarado:
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, si ayuda a entender lo que estoy tratando de hacer: Estoy tratando de identificar si hay registros TreatmentPlanDetail
de este Patient
donde el Payer
autorización requiere una receta para este ServiceType
, pero o bien no hay ServicePerscription
registro, o ha expirado.)
Ahora, aquí está lo que mi código C # es así:
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 };
Vaya, no se compila! Por alguna razón (me gustaría una explicación) no puedo usar ese booleano literal dentro de la combinación de igualdad! Bien, lo dejaré fuera, y filtrar las cosas "RequiresPrescription" más adelante ...
...
join pstr in LinqUtils.GetTable<PayerServiceTypeRules>().DefaultIfEmpty()
on new { auth.PayerID, tpd.ServiceTypeID } equals new { pstr.PayerID, pstr.ServiceTypeID }
...
... y ahora se compila - pero cuando corro, me sale un "Referencia a objeto no establecida" excepción en esta línea. DUH! Por supuesto que hay un nulo en allí! ¿Cómo, si se supone que para llevar a cabo una comparación con una combinación izquierda, si no se le permite hacer referencia al objeto en el lado derecho, que podría potencialmente ser nulo?
Así que, ¿cómo se supone que hacer una combinación izquierda utilizando múltiples campos?
Solución
Creo que es necesario utilizar la palabra clave into
y resolver DefaultIfEmpty de los niños perdidos () después la unión, no antes:
...
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()
es, probablemente, apareciendo un nulo porque el DataTable devuelta contiene ninguna fila , por tanto, la causa de su excepción. Tenga en cuenta toda la declaración después de in
se ejecutará antes de seleccionar en ella, que no es el comportamiento deseado. Desea que las filas coincidentes o nula si no existen filas coincidentes.
Para el problema booleano, es un problema de nomenclatura (nada se compara con "RxReq" en el lado derecho y nada se compara con "RequiresPrescription" en el lado izquierdo). Intenta nombrar el "RequiresPrescription" true
como lo he hecho anteriormente (o el nombre de la parte derecha pstr.RequiresPrescription
"RxReq").