Я задал вопрос ранее о почему левые соединения в Linq не могут использовать определенные отношения; на сегодняшний день у меня нет удовлетворительного ответа.
Теперь, на параллельном треке, я согласился с тем, что мне нужно использовать ключевое слово join
так, как если бы между моими объектами не было отношения, и я пытаюсь выяснить, как выразить свой запрос в Linq, Проблема заключается в конгломерации левых объединений между несколькими таблицами с несколькими полями, участвующими в соединении. Нет никакого способа упростить это, так что здесь SQL во всей своей немаркированной славе:
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, если это помогает понять, что я пытаюсь сделать: я пытаюсь определить, есть ли записи TreatmentPlanDetail
для этого Patient
, где для авторизации Payer
требуется рецепт для этого ServiceType
, но нет либо записи ServicePerscription
, либо истек.)
Теперь, как выглядит мой код на С#:
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 };
Упс, не компилируется! По какой-то причине (я бы хотел объяснить) я не могу использовать этот буквальный логический элемент внутри equijoin! Хорошо, я оставлю это и отфильтровать материал "RequiresPrescription" позже...
...
join pstr in LinqUtils.GetTable<PayerServiceTypeRules>().DefaultIfEmpty()
on new { auth.PayerID, tpd.ServiceTypeID } equals new { pstr.PayerID, pstr.ServiceTypeID }
...
... и теперь он компилируется - но когда я запустил, в этой строке я получаю исключение "Object reference not set". DUH! Конечно, там есть нуль! Как еще вы должны выполнить сравнение с левым соединением, если вам не разрешено ссылаться на объект с правой стороны, который потенциально может быть пустым?
Итак, как вы должны делать левое соединение, используя несколько полей?