5

LinqtoEntitiesで次のことを実現したいと思います。

アプリケーションがない、またはアプリケーションのステータスが!= 4(完了)のすべての問い合わせを取得する

select e.*
from Enquiry enq
left outer join Application app
 on enq.enquiryid = app.enquiryid
where app.Status <> 4 or app.enquiryid is null

Linq to EntitiesでサポートされていないDefaultIfEmpty()を使用せずにこれを行ったことはありますか?

次のようなIQueryableクエリにフィルタを追加しようとしています。

IQueryable<Enquiry> query = Context.EnquirySet; 

query = (from e in query 
         where e.Applications.DefaultIfEmpty()
                             .Where(app=>app.Status != 4).Count() >= 1 
         select e);

ありがとうマーク

4

5 に答える 5

10

EF 4.0以降では、LEFT JOIN構文が少し異なり、クレイジーな癖があります。

var query = from c1 in db.Category 
        join c2 in db.Category on c1.CategoryID equals c2.ParentCategoryID  
        into ChildCategory 
        from cc in ChildCategory.DefaultIfEmpty() 
        select new CategoryObject  
        { 
            CategoryID = c1.CategoryID,  
            ChildName = cc.CategoryName 
        } 

このクエリの実行をSQL​​ServerProfilerでキャプチャすると、実際にLEFTOUTERJOINが実行されていることがわかります。ただし、Linq-to-Entityクエリに複数のLEFT JOIN( "Group Join")句がある場合、上記の構文が使用されている場合でも、self-join句は実際にはINNERJOINのように実行される可能性があります。

その解決策は?クレイジーで、MSによれば、間違っているように聞こえますが、結合句の順序を変更することでこれを解決しました。自己参照のLEFTJOIN句が最初のLinqグループ結合である場合、SQLプロファイラーはINNERJOINを報告しました。自己参照のLEFTJOIN句がLASTLinqグループ結合であった場合、SQLプロファイラーはLEFTJOINを報告しました。

于 2012-08-01T15:39:15.790 に答える
6

これを行う:

IQueryable<Enquiry> query = Context.EnquirySet; 

query = (from e in query 
         where (!e.Applications.Any()) 
               || e.Applications.Any(app => app.Status != 4)
         select e);

SQLの「間抜け」で「外部結合」となる問題をLINQが処理していることはまったくわかりません。それを理解するための鍵は、表形式の結果セットではなく、null許容プロパティを持つオブジェクトグラフの観点から考えることです。

Any()はSQLのEXISTSにマップされるため、場合によってはCount()よりもはるかに効率的です。

于 2009-10-01T15:23:50.973 に答える
3

皆さんの助けに感謝します。私は最終的にこのオプションを選択しましたが、あなたのソリューションは私の知識を広げるのに役立ちました。

IQueryable<Enquiry> query = Context.EnquirySet;

query = query.Except(from e in query
                     from a in e.Applications
                     where a.Status == 4
                     select e);
于 2009-10-01T15:50:05.713 に答える
1

Linqのアウターを処理する間抜けな(非標準の読み取り)方法のため、DefaultIfEmpty()を使用する必要があります。

次に、Linq-To-Entitiesクエリを2つのIEnumerableに実行し、DefaultIfEmpty()を使用してそれらを左結合します。次のようになります。

IQueryable enq = Enquiry.Select();
IQueryable app = Application.Select();
var x = from e in enq
join a in app on e.enquiryid equals a.enquiryid
into ae
where e.Status != 4
from appEnq in ae.DefaultIfEmpty()
select e.*;

Linq-To-Entitiesで実行できないからといって、生のLinqで実行できないわけではありません。

(注:誰かが私に反対票を投じる前に...はい、私はこれを行うためのよりエレガントな方法があることを知っています。私はそれを理解できるようにしようとしているだけです。それは重要な概念ですよね?)

于 2009-10-01T14:14:59.213 に答える
1

もう1つ考慮すべきことは、nullをチェックせずに(into構文を使用して)左結合グループからwhere句のプロパティを直接参照する場合でも、EntityFrameworkはLEFTJOINをINNERJOINに変換します。

これを回避するには、クエリの「fromxinleftJoinedExtent」の部分を次のようにフィルタリングします。

var y = from parent in thing
        join child in subthing on parent.ID equals child.ParentID into childTemp
        from childLJ in childTemp.Where(c => c.Visible == true).DefaultIfEmpty()
        where parent.ID == 123
        select new {
            ParentID = parent.ID,
            ChildID = childLJ.ID
        };

匿名型のChildIDはnull許容型になり、これが生成するクエリはLEFTJOINになります。

于 2014-01-13T22:16:17.183 に答える