10

ICollectionを使用して親子関係を使用したEntityFrameworkCodeFirstを使用しています。

public class Person
{
   public string UserName { get;set}
   public ICollection<Blog> Blogs { get; set;}
}

public class Blog
{
   public int id { get; set; }
   public string Subject { get; set; }
   public string Body { get; set; }
}

これまでのところ、すべてが正常に機能していますが、私の懸念は、ある人のブログを取得したいときはいつでも、次のように取得することです。

var thePerson = _context.Persons.Where(x => x.UserName = 'xxx').SingleOrDefault();
var theBlogs = thePerson.Blogs.OrderBy(id).Take(5);

これで、行が実行されると、その人のすべてのブログがメモリに読み込まれ、メモリから並べ替えと選択が行われることがわかりました。これは、ブログの数が多い人の記録には理想的ではありません。ブログの子をIQuery可能にして、メモリにプルする前にSQLデータベースで並べ替えと選択が行われるようにします。

自分のコンテキストでブログをIQueryableとして宣言できるので、次のように直接クエリできます。

var theBlogs = _context.Blogs.Where(.....)

しかし、それは設計上の選択のために私には実行可能ではありません。シリアル化の問題のために、循環参照をできるだけ避けたいと思います。そのため、子の親エンティティについては言及しませんでした。

私は、ブログでAsQueryable()メソッドを次のように呼び出すことができることを発見しました。

var theBlogs = thePerson.Blogs.AsQueryable().OrderBy(id).Take(5);

それは私にとって魔法のように見え、真実には良すぎるようです。だから私の質問。このAsQueryableは、実際にICollectionをIQueryableとして作成し、SQL Serverですべてのクエリプロセスを作成しますか(遅延読み込み)、またはブログが以前のようにメモリに読み込まれるキャストですが、インターフェイスをICollectionからIQueryableに変更しますか?

4

2 に答える 2

7

したがって、実際には、ナビゲーションプロパティを記述IQueryable<T> できないように見えます。

あなたができることは、ナビゲーションプロパティを以下に追加することですBlog

public class Blog
{
   public int id { get; set; }
   public string Subject { get; set; }
   public string Body { get; set; }
   public virtual Person Owner { get; set; }
}

それから、次のようにクエリを実行して、すべてがメモリにロードされないようにすることができます。

var thePerson = _context.Persons.Where(x => x.UserName = 'xxx').SingleOrDefault();
var results = _context.Blogs.Where(z => z.Person.Name = thePerson.Name).OrderBy(id).Take(5)

LINQPadを試して、LINQがSQLにどのように変換されるか、およびDBから実際に何が要求されているかを確認することをお勧めします。

于 2012-02-08T10:15:36.117 に答える
3

より良いアプローチは、Ladislavの回答に記載されています。あなたの場合:

var theBlogs = _context.Entry(thePerson)
                       .Collection(x => x.Blogs)
                       .Query()
                       .OrderBy(x => x.id)
                       .Take(5);
于 2012-02-09T03:11:30.607 に答える