2

要約:エンティティの子コレクションのLINQクエリを取得して、「LINQ-to-Objects」ではなく「LINQ-to-Entities」を使用する、つまり、クエリプロバイダーを使用して生成するためのオプションは何ですか。通常の列挙を実行するのではなくSQL?これは、EF5、DbContext、およびPOCOエンティティを使用しています。

別の見方をすると、すべてのLINQクエリを変更せずに、エンティティの子コレクション(ICollection <>タイプ)を古いスタイルのEF1エンティティのEntityCollection <>プロパティのように動作させるにはどうすればよいですか?

これが私の状況です:

ObjectContextとデフォルトで生成されたエンティティの代わりにDbContextとPOCOエンティティを使用するように切り替えるEntityFramework5プロジェクトがあります。

コード全体で、次のようなクエリがあります。

var thirdEntities = from secondEntity in firstEntity.SecondEntities
    select secondEntity.ThirdEntity;

firstEntity.SecondEntitiesのタイプはEntityCollectionであったため、これは以前はデータベースヒットが1つだけでした。これにより、LINQ to Entitiesが使用され、LINQステートメント全体がSQLに変換されました。

ただし、DbContextとPOCOの使用に切り替えた場合、上記のステートメントにより、データベースが多数ヒットするようになりました。問題の原因となるPOCOクラスプロパティは次のとおりです。

public class FirstEntity {
  public FirstEntity() {
    this.SecondEntities = new HashSet<SecondEntity>();
  }

  public virtual ICollection<SecondEntity> SecondEntities {get; set;}
}

これは、firstEntity.SecondEntitiesがタイプICollection(実際のタイプのHashSet)になっているためです。遅延読み込みがオンになっているため、データベースがヒットしてfirstEntity.SecondEntitiesを埋め、次にその結果がX回列挙されてsecondEntity.ThirdEntityの各インスタンスが埋められます。

私が見つけた解決策の1つは、最初のクエリを次のように変更することです。

var thirdEntities = from secondEntity in dbContext
    .Entry(firstEntity)
    .Collection(e => e.SecondEntities)
    .Query()
    select secondEntity.ThirdEntity;

しかし、私はこれをしたくありません。すべてのLINQクエリを変更する必要がないように、POCOをなんらかの方法で変更したいと思います。

4

1 に答える 1

3

私の理解と私が実行したテストでは、のLINQクエリEntityCollection<T>がLINQ-to-Entitiesであるというのは正しくありません。実際、これはLINQ-to-Objectsであり、SQLを作成したりデータベースにアクセスしたりすることなく、メモリ内でのみ実行されます(EF> = 4.0での遅延読み込みを除く)。

例として:

using (var ctx = new MyEntities())
{
    var firstEntity = ctx.FirstEntities.First(f => f.ID == 1);
    var thirdEntities = (from secondEntity in firstEntity.SecondEntities
                         select secondEntity.ThirdEntity).ToList();
}

ここで、最初のクエリはもちろんLINQ-to-EntitiesでありfirstEntity、データベースからロードされます。ThirdEntity2番目のクエリは、SQLプロファイラーで確認したように選択する単一のSQLクエリを作成しません。firstEntity.SecondEntitiesEF 1では、最初のクエリで熱心に読み込まれておらず(したがって、コレクションが空であるため)、EF 1は遅延読み込みをサポートしていないため、2番目のクエリは実際には何もしません。EF 4では、遅延読み込みクエリがトリガーされて完全なコレクションが読み込まれ、次に読み込みするコレクション内の(一意の)要素ごとに1つの追加の遅延読み込みクエリがトリガーされますThirdEntity(これもテストしました)。 POCOを使用します。

EntityCollection<T>を実装していないので、結果は私にとって驚くべきことではありませんIQueryable<T>。署名は次のとおりです。

public sealed class EntityCollection<TEntity> : RelatedEnd, ICollection<TEntity>,
    IEnumerable<TEntity>, IEnumerable, IListSource

このようなコレクションに対して実行するすべてのLINQクエリは、拡張メソッドを使用しますIEnumerable<T>。これは、次のことを意味します。LINQ-to-Objectsです。

CreateSourceQueryただし、最後のコードスニペットと同様に、EntityCollection<T>:に適用することでLINQ-to-Entities/explicitloadingを有効にできます。

var thirdEntities =
    (from secondEntity in firstEntity.SecondEntities.CreateSourceQuery()
     select secondEntity.ThirdEntity).ToList();

CreateSourceQueryObjectQuery<T>データベースから完全なナビゲーションコレクションをロードするために必要なSQLを表すを返します。このクエリは実際、より多くのフィルタリングまたは選択を実行するように改良でき、データベース内のLINQ-to-Entitiesとして実行されます。

POCOとは異なるクエリ動作を観察したことが確実な場合はEntityCollection<T>、これを再現するための簡単なサンプルモデルを提供できれば役立ちます。現時点では、これがどのように発生するのかわかりません。

于 2012-09-28T13:36:35.927 に答える