2016-04-28 11 views
1

この問題に取り組むためのアドバイスを探しています。多くの左外部結合を持つこの大規模なSQLクエリがあります。ここでLINQで左外部結合を持つ大規模な複雑なクエリを再作成

はクエリです:

Select Top 1 WA.BHATUS_ID, WA.[CRMBHG_WORKINGACCOUNT_ID], BA.BHATUS_ID, BA.[CRMBHG_BILLINGACCOUNT_ID], BAD.BHATUS_ID, [BAD].[CRMBHG_BILLINGADDRESS_ID], SAD.BHATUS_ID, [SAD].[CRMBHG_SERVICEADDRESS_ID], C.BHATUS_ID, [C].[CRMBHG_CONTACT_ID] 
From BillingHiBHory As BH With (NoLock) 
    Left Outer Join WorkingAccount As WA With (NoLock) 
     On WA.UniversalAccountId = BH.UniversalAccountId 
      And WA.BillingRegion = BH.BillingRegion 
    Left Outer Join BillingAccount As BA With (NoLock) 
     On BA.UniversalAccountId = BH.UniversalAccountId 
      And BA.BillingRegion = BH.BillingRegion 
    Left Outer Join BillingAddress As BAD With (NoLock) 
     On BAD.Grouping = BH.Grouping 
      And BAD.SubGrouping = BH.SubGrouping 
      And BAD.BillingRegion = BH.BillingRegion 
    Left Outer Join dbo.SubScriberInfo SUB With (NoLock) 
      On SUB.Grouping = BH.Grouping 
      And SUB.SubGrouping = BH.SubGrouping 
      And SUB.BillingRegion = BH.BillingRegion 
    Left Outer Join ServiceAddress As SAD With (NoLock) 
     On SAD.ControlNumberAssigned = SUB.ServceControlNum 
      And SAD.BillingRegion = SUB.BillingRegion 
    Left Outer Join Contact As C With (NoLock) 
     On BH.AccountNum = C.AccountNum 
      And BH.BillingRegion = C.BillingRegion 
Where BH.Grouping = @Grouping 
    And BH.SubGrouping = @SubGrouping 
Order By BH.SequenceOrder, WA.StatusDate Desc, BA.StatusDate Desc, BAD.StatusDate Desc, SAD.StatusDate Desc, C.StatusDate Desc 

ここでLINQの構文で私の最初の亀裂があります...

var statusIds = (
    from wa in db.WorkingAccount 
    from ba in db.BillingAccount 
    from bad in db.BillingAddress 
    from si in db.SubscriberInfo 
    from sad in db.ServiceAddress 
    from c in db.CRMSTG_CONTACT 
    where wa.UniversalAccountId == UniversalSubscriberId && wa.BillingRegion == BillingRegion 
    where ba.UniversalAccountId == UniversalSubscriberId && ba.BillingRegion == BillingRegion 
    where bad.Grouping == Grouping && bad.SubGrouping == SubGrouping && bad.BillingRegion == BillingRegion 
    where si.Grouping == Grouping && si.SubGrouping == SubGrouping && si.BillingRegion == BillingRegion 
    where sad.ControlNumberAssigned == si.ServceControlNum && sad.BillingRegion == BillingRegion 
    where c.AccountNum == AccountNumber && c.BillingRegion == BillingRegion 
    orderby wa.StatusDate descending, ba.StatusDate descending, bad.StatusDate descending, sad.StatusDate descending, c.StatusDate descending 
    select new 
    { 
     workingAddressStatusId = wa.StatusId, 
     billingAccountStatusId = ba.StatusId, 
     billingAddressStatusId = bad.StatusId, 
     serviceAddressStatusId = sad.StatusId, 
     contactStatusId = c.StatusDate 
    } 
    ).FirstOrDefault(); 

この大部分は動作しますが、大きなハックのように感じています。これが落ちるのは、StatusId値の1つがnullに戻り、statusIdsがnullになった場合です。

私はこれを行うためのよりよい方法があると確信しています。私は提案に開放されています。

はい、私はTSQLの「With(NoLock)」オプションに関連するリスクを認識しています。私たちは非常にビジー状態のデータベースのセカンダリアプリであり、ブロックを作成したくありません請求およびサポートスタッフが作業を行うためチェーンが必要です。私たちがやっていることに対して、NoLockは問題ではありません。アグリゲータを使用して複数のユニオン・クエリを実行しているようなわけではありません。 ;)

+0

やあ、良い一日、可能であれば、あなたはそれぞれのドメイン構造を含めることができます。StatusIdタイプがintある場合たとえば、あなたはこのようなものを使用する必要がありますか? – gab

+0

ああ、データ型が矛盾していて、AS400データベースからMSSQLデータベースにステージングされてから、MSSQLデータベースに移動して移動する前に、私がリンクしているキーの本質を書きましょう。 – amber

+1

私の意見では、これがレガシーデータベースの一部をリファクタリングする場合、このクエリをストアドプロシージャに保存し、この特定のsqlを生成するためにlinqを処理しようとするのではなく、EFがspを呼び出すようにします。私は、複数の左結合を解決するために、データモデルをそれほど多く必要としないように調整します。 – jkerak

答えて

1

左外部結合の数が多く、左外部結合がLINQでは自然にサポートされていませんが、パターンはよく知られています。左外部結合複合キーjoin clause (C# Reference)セクションので、あなたが必要とするすべてのパターンに従うことです:考慮すべき

from bh in db.BillingHiBHory 

join wa in db.WorkingAccount 
on new { bh.UniversalAccountId, bh.BillingRegion } 
equals new { wa.UniversalAccountId, wa.BillingRegion } 
into bh_wa from wa in bh_wa.DefaultIfEmpty() // this turns the above (inner) join into left outer join 

join ba in db.BillingAccount 
on new { bh.UniversalAccountId, bh.BillingRegion } 
equals new { ba.UniversalAccountId, ba.BillingRegion } 
into bh_ba from ba in bh_ba.DefaultIfEmpty() 

join bad in db.BillingAddress 
on new { bh.Grouping, bh.SubGrouping, bh.BillingRegion } 
equals new { bad.Grouping, bad.SubGrouping, bad.BillingRegion } 
into bh_bad from bad in bh_bad.DefaultIfEmpty() 

join si in db.SubscriberInfo 
on new { bh.Grouping, bh.SubGrouping, bh.BillingRegion } 
equals new { si.Grouping, si.SubGrouping, si.BillingRegion } 
into bh_si from si in bh_si.DefaultIfEmpty() 

join sad in db.ServiceAddress 
on new { si.ServceControlNum, si.BillingRegion } 
equals new { sad.ControlNumberAssigned, sad.BillingRegion } 
into si_sad from sad in si_sad.DefaultIfEmpty() 

join c in db.CRMSTG_CONTACT 
on new { bh.AccountNum, bh.BillingRegion } 
equals new { c.AccountNum, c.BillingRegion } 
into bh_c from c in bh_c.DefaultIfEmpty() 

where bh.Grouping == Grouping 
    && bh.SubGrouping == SubGrouping 

// ... (the rest) 

一つの詳細は、左外部結合のright部分から非NULL可能フィールドを選択するときにNULL値可能なキャストを含めることです。

select new 
{ 
    workingAddressStatusId = (int?)wa.StatusId, 
    // ... 
} 
+0

コードサンプルに匿名型のバグがあります。メンバー名を含める必要があります。私は本当に速く戻ってくるタイムアウトに問題がありますが、この答えはこの問題を解決します。 'new {grouping = bh.Grouping、subGrouping = bh.SubGrouping、... ' – amber

+0

また、匿名型を使用して操作を実行し、同等の操作を行うことは本当に滑らかです。私はそれを考えなかった。あなたのメンバー名が同じでなければならない、あるいはコンパイル時にエラーが出ることを知りましたが。 – amber

+0

実際には、匿名型のフィールドの名前は明示的に提供する必要はなく、ほとんどの場合推論されます。私は明示的に異なる名前を持つ 'si_sad'結合フィールドの1つを明記するのを忘れました。なぜなら、2つの匿名型は名前の1つとみなされ、フィールドの名前と型が一致すれば同じであるからです。 –

関連する問題