Я задал вопрос ранее о почему левые соединения в 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! Конечно, там есть нуль! Как еще вы должны выполнить сравнение с левым соединением, если вам не разрешено ссылаться на объект с правой стороны, который потенциально может быть пустым?
Итак, как вы должны делать левое соединение, используя несколько полей?