結合に複数のフィールドがある場合、Linq で結合を解除するにはどうすればよいですか?
-
11-09-2019 - |
質問
先ほど質問させていただきましたが、 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
(参考までに、私がやろうとしていることを理解するのに役立つ場合:あるかどうかを特定しようとしています TreatmentPlanDetail
このための記録 Patient
どこで認可するのか Payer
これには処方箋が必要です ServiceType
, 、しかし、どちらかがありません ServicePerscription
記録がないか、有効期限が切れています。)
さて、私の C# コードは次のようになります。
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 };
おっと、コンパイルできません!何らかの理由で (説明が欲しいのですが) 等結合内でリテラルのブール値を使用することができません。わかりました。それは省略し、後で「RequiresPrescription」のものを除外します...
...
join pstr in LinqUtils.GetTable<PayerServiceTypeRules>().DefaultIfEmpty()
on new { auth.PayerID, tpd.ServiceTypeID } equals new { pstr.PayerID, pstr.ServiceTypeID }
...
...これでコンパイルは完了しましたが、実行すると、この行で「オブジェクト参照が設定されていません」という例外が発生します。 当たり前だ! もちろんそこにはヌルがあります!右側のオブジェクトを参照することが許可されていない場合、潜在的に null になる可能性がある場合、左結合との比較を他にどのように実行すればよいでしょうか?
では、複数のフィールドを使用して左結合を行うにはどうすればよいでしょうか?
解決
を使用する必要があると思います into
キーワードを指定し、欠落している子の DefaultIfEmpty() を解決します。 後 結合の前ではなく、
...
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()
おそらく null が返されるのは、 返された DataTable には行が含まれていません, したがって、例外が発生します。後のステートメント全体に注目してください in
は選択する前に実行されますが、これは望ましい動作ではありません。一致する行が必要です。一致する行が存在しない場合は null が必要です。
ブール値の問題の場合、これは名前付けの問題です (右側の「RxReq」に一致するものはなく、左側の「RequiresPrescription」に一致するものはありません)。名前を付けてみてください true
上記のように「RequiresPrescription」(または右側の名前を付けます) pstr.RequiresPrescription
「RxReq」)。