17


6

Entity Frameworkクエリで「含む」テーブルをフィルター処理する

これは、Entity Framework for .NET 3.5用です。

テーブルをクエリし、1対多の関係の「多」テーブルのコレクションを含める必要があります。 クエリの一部としてそのコレクションをフィルター処理しようとしています-Entity Frameworkが初めてであり、それを理解するのに苦労しています。

簡単な例:著者には書籍があり、書籍にはIsFiction列があります。 すべてのフィクションの本とともに、著者のフィルターされたリストが必要です。

フィルターがなければ、簡単です。

var q = from a in db.Authors.Include("Books")
        where a.BirthYear > 1900
        select a;

事実の後にフィルタリングできます。次のようなものです。

var fictionBooks = a.Books.Where(b => b.IsFiction);

しかし問題は、元のクエリが既に実行されていて、それらの結果が含まれていることであり、これは不必要なデータベース処理です。

次のように個別にクエリできます:

var q = from a in db.Authors where a.BirthYear > 1900 select a;
foreach (var a in q)
{
    var books = from b in db.Books
                where ((b.Author.Id == a.Id) && (b.IsFiction))
                select b;
}

しかし、もちろん、それはすべての著者に対する1回の呼び出しであり、これも避ける必要があります。

次のように後方に移動できます:

var allBooks = from b in db.Books.Include("Author")
               where b.IsFiction
               select b;

しかし、私は元の問題に戻りましたが、今は本の代わりに著者の側にいます。

すべてを網羅するソリューションが必要です-私はSQLでそれをかなり簡単に行うことができます:

select * from author a
left join book b on a.id = b.author_id and b.is_fiction = 1
where a.birth_year > 1900

助言がありますか?

1 Answer


14


今後の方法:

var q = from a in db.Authors.Include("Books")
        where a.BirthYear > 1900
        select new {
            Author = a,
            FictionBooks = a.Books.Where(b => b.IsFiction)
        };

あなたの質問の下部にあるSQLから派生した別の方法:

var q = from a in db.Authors
        from b in db.Books.Include("Author")
        where a.BirthYear > 1900 && b.IsFiction && a.Id == b.Author.Id
        select new { Author = a, Book = b };

これら2つの主な違いは、最初の1つは基本的に著者のコレクションと各著者のフィクションの本のリスト(空の場合もある)を提供することです。一方、2番目は著者と書籍のペアのコレクションを提供します(したがって、フィクションの書籍を持たない著者は返されません)。