web-dev-qa-db-ja.com

Entity Frameworkの条件付きInclude()

同様の質問に対するいくつかの回答を見てきましたが、自分の問題に回答を適用する方法を考え出すことはできません。

var allposts = _context.Posts
            .Include(p => p.Comments)
            .Include(aa => aa.Attachments)
            .Include(a => a.PostAuthor)
            .Where(t => t.PostAuthor.Id == postAuthorId).ToList();

添付ファイルは、作成者(作成者タイプ)または投稿者(投稿者タイプ)によってアップロードできます。私がやりたいのは、添付ファイルの所有者がAuthorタイプのAttachmentsのみを取得することです。

私はこれが機能せず、エラーが発生することを知っています:

.Include(s=>aa.Attachments.Where(o=>o.Owner is Author))

ここでフィルターされた投影について読みました

編集-記事へのリンク: http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx

しかし、私はちょうどそれを回避することはできません。

すべての投稿が必要なため、最後のwhere句にフィルターを含めたくありませんが、著者に属する投稿の添付ファイルのみを取得したいです。

編集2:-要求された投稿スキーマ

public abstract class Post : IPostable
{

    [Key]
    public int Id { get; set; }

    [Required]
    public DateTime PublishDate { get; set; }

    [Required]
    public String Title { get; set; }

    [Required]
    public String Description { get; set; }

    public Person PostAuthor { get; set; }
    public virtual ICollection<Attachment> Attachments { get; set; }
    public List<Comment> Comments { get; set; }
}
15
grayson

投稿したリンクから、1対多(または多対1)の関係でのみトリックが機能することを確認できます。この場合、Post-Attachmentは1対多の関係である必要があるため、完全に適用可能です。必要なクエリは次のとおりです。

//this should be disabled temporarily
_context.Configuration.LazyLoadingEnabled = false;
var allposts = _context.Posts.Where(t => t.PostAuthor.Id == postAuthorId)
                       .Select(e => new {
                           e,//for later projection
                           e.Comments,//cache Comments
                           //cache filtered Attachments
                           Attachments = e.Attachments.Where(a => a.Owner is Author),
                           e.PostAuthor//cache PostAuthor
                        })
                       .AsEnumerable()
                       .Select(e => e.e).ToList();
11
Hopeless

遅延読み込みを防ぐため、virtualナビゲーションプロパティからAttachmentsキーワードを削除します。

public ICollection<Attachment> Attachments { get; set; }

最初の方法:2つの個別のクエリを発行します。1つは投稿用、もう1つは添付ファイル用で、残りはリレーションシップの修正で処理します。

List<Post> postsWithAuthoredAttachments = _context.Posts
    .Include(p => p.Comments) 
    .Include(p => p.PostAuthor)
    .Where(p => p.PostAuthor.Id == postAuthorId)
    .ToList();

List<Attachment> filteredAttachments = _context.Attachments
    .Where(a => a.Post.PostAuthor.Id == postAuthorId)
    .Where(a => a.Owner is Author)
    .ToList()

関係の修正により、投稿のナビゲーションプロパティを介してこれらのフィルターされた添付ファイルにアクセスできます。

2番目の方法:データベースへの1つのクエリとそれに続くメモリ内クエリ:

var query = _context.Posts
    .Include(p => p.Comments) 
    .Include(p => p.PostAuthor)
    .Where(p => p.PostAuthor.Id == postAuthorId)
    .Select(p => new 
        {
            Post = p,
            AuthoredAttachments = p.Attachments
                Where(a => a.Owner is Author)
        }
    );

ここでは匿名型を使用します

var postsWithAuthoredAttachments = query.ToList()

または、匿名型を回避するためにViewModelクラスを作成します。

List<MyDisplayTemplate> postsWithAuthoredAttachments = 
     //query as above but use new PostWithAuthoredAttachments in the Select

または、本当に投稿を展開したい場合:

List<Post> postsWithAuthoredAttachments = query.//you could "inline" this variable
    .AsEnumerable() //force the database query to run as is - pulling data into memory
    .Select(p => p) //unwrap the Posts from the in-memory results
    .ToList()
4
Colin

拡張メソッドの この実装 を使用できます(例)Include2()。その後、次を呼び出すことができます。

_context.Posts.Include2(post => post.Attachments.Where(a => a.OwnerId == 1))

上記のコードには、Attachment.OwnerId == 1

3
Jan Palas