web-dev-qa-db-ja.com

LINQ to Entity:複数の結合条件

LINQおよび複数の結合に関する多数の投稿があります。しかし、私は自分が作りたいと思う参加に対する解決策を見つけていません。

同等のSQLは次のようになります。

SELECT * FROM table1 a
LEFT JOIN table2 b ON a.col1 = b.key1 AND
a.col2 = b.key2 AND
b.from_date <= now() AND
b.deleted = 0;

これは私が試みた多数のlinqクエリの1つです

var query = (from x in context.table1
             join y in context.table2 on new {x.col1, x.col2} equals {b.key1, b.key2} 
             into result
             from result......

日付と削除済みフラグの追加条件を追加するにはどうすればよいですか? .Where条件を使用すると、これは左結合ではなく内部結合として扱われます。

33
Kman

別の方法は

var query = (from x in context.table1 
             join y in context.table2 on 
             new  {
                  Key1 = x.col1, 
                  Key2 = x.col2,
                  Key3 = true,
                  Key4 = true
                 }
             equals
             new {
                  Key1 = y.key1, 
                  Key2 =  y.key2,
                  Key3 = y.from_date< DateTime.Now,
                  Key4 = !y.deleted
                 }  
             into result
from r in result.DefaultIfEmpty()
select new  {x.Something, r.Something}
54

LINQは、結合構文と古いANSI-82 WHERE構文の両方をサポートしています。後者を使用すると、内部結合で探していることを行うことができます

var nowTime = DateTime.Now;
var query = from a in context.table1
            from b in context.table2
            where a.col1 == b.key1
                 && a.col2 == b.key2 
                 && b.from_date < nowTime
                 && b.deleted == false
            select ???;

外部結合の場合、whereとselectのハイブリッドを使用した構文を好みます。 (LINQクエリの順序は、SQLで行うことを模倣する必要はなく、順序はより柔軟であることに注意してください。)

var nowTime = DateTime.Now;
var query = from b in context.table2
            from a1 in a.Where(a2 => 
                b.key1 = a.col && 
                b.key2 = a.col2 &&
                b.from_date < nowTime &&
                b.deleted == false).DefaultIfEmpty()
            select ???;
15
Jim Wooley

匿名オブジェクトのプロパティの命名に問題がありました:

var subscriptions = context.EmailSubscription.Join(context.EmailQueue,
                    es => new { es.Id, 9 },
                    eq => new { eq.EmailSubscriptionId, eq.EmailTemplateId },
                    (es, eq) => new { es.Id, eq.Id }
                ).ToList();

コンパイラは満足していなかったので、上記の答えは何が間違っていたのかを理解するのに役立ち、ここに私の作業ソリューションがあります。愚かな間違いを見つけるのに時間がかかりました:):

var subscriptions = context.EmailSubscription.Join(context.EmailQueue,
                    es => new { EmailSubscriptionId = es.Id, EmailTemplateId  = 9 },
                    eq => new { eq.EmailSubscriptionId, eq.EmailTemplateId },
                    (es, eq) => new { es.Id, eq.Id }
                ).ToList();
2
tonco

2番目のクエリで1番目の結果セットをフィルタリングすることはできませんか?

var query = (from x in context.table1 
             join y in context.table2 on new {x.col1, x.col2} equals {b.key1, b.key2}  
             into result
query = from x in query
        where ...

それはうまくいくでしょうか?

1
james lewis

@Muhammad Adeel Zahidの回答に加えて、次のようないくつかの条件も使用できます。

new
{
Key1 = ppl.PeopleId,
Key2 = true,
Key3 = true
}
equals
new
{
Key1 = y.PeopleId,
Key2 = !y.IsDeleted,
Key3 = (y.RelationshipType == 2 || y.RelationshipType == 4)
}
0
Leandro