Comment pouvez-vous vous joignez à gauche dans LINQ s'il y a plus d'un champ dans la jointure?

StackOverflow https://stackoverflow.com/questions/1093494

Question

J'ai posé une question tout à l'heure pourquoi se joint à gauche dans LINQ ne peut pas utiliser les relations définies ; à ce jour, je ne l'ai pas obtenu une réponse satisfaisante.

Maintenant, sur une piste parallèle, je l'ai accepté que je dois utiliser le mot clé join comme s'il n'y avait pas de relation définie entre mes objets, et je suis en train de travailler sur la façon d'exprimer ma requête dans LINQ. Le problème est, il est un agglomérat de gauche des jointures entre plusieurs tables, avec plusieurs champs impliqués dans la jointure. Il n'y a aucun moyen de simplifier cela, voici donc le SQL dans toute sa gloire démasqué:

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

(Pour votre information, si elle aide à comprendre ce que je suis en train de faire: Je suis en train d'identifier s'il y a des enregistrements TreatmentPlanDetail pour ce Patient où l'autorisation Payer nécessite une ordonnance pour cette ServiceType, mais il n'y a pas non plus ServicePerscription enregistrement, ou il est arrivé à expiration.)

Maintenant, voici ce que mon code C # ressemble à:

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, ne compile pas! Pour une raison quelconque (j'aimerais une explication) Je ne peux pas utiliser ce booléen littéral dans la équijointure! Très bien, je vais le laisser sortir et filtrer les choses « de RequiresPrescription » plus tard ...

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

... et maintenant il compile - mais quand je cours, je reçois une exception « référence d'objet non défini » sur cette ligne. DUH! Bien sûr, il y a un nul là-dedans! Sinon, comment êtes-vous censé effectuer une comparaison avec une jointure gauche, si vous n'êtes pas autorisé à référencer l'objet sur le côté droit, qui pourrait potentiellement être nulle?

Alors, comment êtes-vous censé faire une jointure gauche en utilisant plusieurs champs?

Était-ce utile?

La solution

Je pense que vous devez utiliser le mot-clé into et résoudre DefaultIfEmpty () des enfants disparus après la jointure, pas avant:

...
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() tourne probablement une valeur nulle parce que le DataTable retourné ne contient aucune ligne , ce qui provoque votre exception. Notez l'instruction entière après in sera exécutée avant de choisir en elle, ce qui est pas votre comportement souhaité. Vous voulez que les lignes correspondantes ou null s'il existe aucune ligne correspondant.


Pour le problème booléen, il est un problème de nommage (rien ne correspond « RxReq » sur le côté droit et rien ne correspond à « RequiresPrescription » sur le côté gauche). Essayez de nommer le true « RequiresPrescription » comme je l'ai ci-dessus (ou le nom du pstr.RequiresPrescription du côté droit « de RxReq »).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top