3

単純なドメインがあります..

public abstract class UserComment
{
    public string Text { get; set; }
}

public class BlogComment : UserComment
{
    public Blog Blog { get; set; }
}

public class PhotoComment : UserComment
{
    public Photo Photo { get; set; }
}

プロパティ Blog と Photo が読み込まれたタイプUserCommentのすべてのエンティティをクエリする方法はありますか?

var comment = DbContext.Set<UserComment>()
    .Include(x => x.Blog) // will not compile
    .Include(x => x.Photo) // will not compile
    .FirstOrDefault();

if (comment is PhotoComment )
{
    string url = (comment as PhotoComment).Photo.Url;
}
if (comment is BlogComment)
{
    var dateCreated = (comment as BlogComment).Blog.DateCreated;
}

ありがとう!

4

1 に答える 1

5

結果を得るには、おそらく 2 つのクエリが必要です。FirstOrDefaultコメントですでに提案したように、最初の要素 ( ) の明示的な読み込みのみが必要な場合は、良いアプローチです。

var comment = DbContext.Set<UserComment>().FirstOrDefault();

if (comment is BlogComment)
    DbContext.Entry(comment as BlogComment).Reference(bc => bc.Blog).Load();
else if (comment is PhotoComment)
    DbContext.Entry(comment as PhotoComment).Reference(pc => pc.Photo).Load();

s のリストをロードする場合UserComment、ロードされた s を反復処理し、UserComment多くのクエリが発生する各要素に対して明示的なロードを呼び出す必要があるため、これは最適なソリューションではありません。

リストの場合、2 つのクエリのみを生成する次のアプローチを使用できます。

IEnumerable<UserComment> blogComments = DbContext.Set<UserComment>()
    .OfType<BlogComment>()
    .Include(bc => bc.Blog)
    .Cast<UserComment>()
    .AsEnumerable();

IEnumerable<UserComment> photoComments = DbContext.Set<UserComment>()
    .OfType<PhotoComment>()
    .Include(pc => pc.Photo)
    .Cast<UserComment>()
    .AsEnumerable();

List<UserComment> comments = blogComments.Concat(photoComments).ToList();

これを使用すると、AsEnumerable()2 つの別個のデータベース クエリが実行され、結果がメモリ内の 1 つのコレクションに連結されます。

LINQ-to-Entities はサポートしていますCastが、何らかの理由で、2 つのAsEnumerable()変換を削除して 1 つのデータベース クエリのみを取得し、データベースで結果を連結することはできません。Includeコードは引き続きコンパイルされますが、無効なパスに関する実行時例外が発生しました。

私はEF 4.1でテストしました。AsEnumerable()EF 5.0 を使用せずにクエリをテストして、それでも失敗するかどうかを確認する価値がある場合があります。

于 2012-10-21T15:30:09.057 に答える