2009-07-07 5 views
12

Hice una pregunta anterior sobre why left joins in Linq can't use defined relationships; hasta la fecha no he recibido una respuesta satisfactoria.¿Cómo te unes a Linq si hay más de un campo en la unión?

Ahora, en una pista paralela, he aceptado que necesito usar la palabra clave join como si no hubiera relación definida entre mis objetos, y estoy tratando de encontrar la manera de expresar mi consulta en Linq. El problema es que es un conglomerado de combinaciones a la izquierda entre varias tablas, con múltiples campos involucrados 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 alguna . TreatmentPlanDetail registros de este Patient donde el Payer autorizar requiere una receta para este ServiceType, pero o bien no hay ServicePerscription registro, o ha expirado)

Ahora, esto es lo que se ve mi C# código como:

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 compila! Por alguna razón (me encantaría una explicación) ¡No puedo usar ese booleano literal dentro de la equijoin! Bien, lo dejaré fuera, y filtrar el "RequiresPrescription" cosas después ...

... 
join pstr in LinqUtils.GetTable<PayerServiceTypeRules>().DefaultIfEmpty() 
on new { auth.PayerID, tpd.ServiceTypeID } equals new { pstr.PayerID, pstr.ServiceTypeID } 
... 

... y ahora 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 allí! ¿De qué otra forma se supone que debes hacer una comparación con una combinación de la izquierda, si no puedes referenciar el objeto del lado derecho, que podría ser nula?

Entonces, ¿cómo se supone que debe hacer una combinación izquierda usando múltiples campos?

+1

Para el problema booleano, ¿no podría ser un problema de nomenclatura (nada coincide con "RxReq" en el lado derecho y nada coincide con "RequiresPrescription" en el lado izquierdo)? Intente nombrar el booleano "RequiresPrescription" o nombre específicamente el pstr.RequiresPrescription "RxReq" del lado derecho. –

Respuesta

14

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 no filas, causando su excepción. Tenga en cuenta que toda la instrucción después de in se ejecutará antes de seleccionarla, que no es el comportamiento deseado. Desea las filas coincidentes o nulo 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). Intente nombrar el true "RequiresPrescription" como lo hice anteriormente (o nombre el lado derecho pstr.RequiresPrescription "RxReq").

+3

... o simplemente ríndete, guarda tu cordura y usa un micro ORM como Dapper.net – niico

Cuestiones relacionadas