2011-08-11 12 views
5

私はEntity Frameworkに慣れてきましたが、私はDBSetオブジェクトの動作のいくつかに戸惑います。 Find()メソッドを呼び出すと、最近追加された(ただしまだ保存されていない)アイテムのコレクションが認識されているように見えますが、DBSetをクエリしようとすると、 。これを回避する簡単な方法はありますか?DBSetのクエリにローカルにキャッシュされた項目を含める方法はありますか?

"Unable to create a constant value of type EntityType. Only primitive types ('such as Int32, String, and Guid') are supported in this context."

internal DbContext Context { get; set; } 
protected DbSet<T> DBSet { get; set; } 

public virtual IEnumerable<T> Get(
    Expression<Func<T, bool>> filter = null, 
    Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, 
    bool ignoreCachedChanges = false) 
{ 
    IQueryable<T> oReturn = DBSet; 

    // This block is intended to adjust the queryable source to account for changes 
    if (!ignoreCachedChanges) 
    { 
     oReturn = oReturn.Except(Context.ChangeTracker.Entries<T>().Where(x => x.State == System.Data.EntityState.Deleted).Select(x => x.Entity)); 
     oReturn = oReturn.Union(Context.ChangeTracker.Entries<T>().Where(x => x.State == System.Data.EntityState.Added).Select(x => x.Entity)); 
    } 
    if (filter != null) 
     oReturn = oReturn.Where(filter); 

    if (orderBy != null) 
     return orderBy(oReturn).ToList(); 
    else 
     return oReturn.ToList(); 
} 

// NOTE: Get By ID uses Find which considers the queued-but-not-yet-applied changes 
public virtual T GetByID(object id) 
{ 
    return DBSet.Find(id); 
} 

:私は、私はこの問題を回避しようとするために行われてきたが、それは私の「追加」チェンジ・セットから項目を反復処理するために開始したとき、私はこのエラーを取得するいくつかのコードを含めています(コンテキストが役立つ場合、私は私の(ローカル)コンテキストに私の特定のテスト環境を満たすアイテムを配置する単体テストを設定したいので、これをやっています...私はただちに適用する必要はありませんこれらの変更は、実際には特定のテストにのみ適用されるためですが、必要に応じて行うことができます。その際、私はリポジトリにクエリされた結果の変更項目が含まれていないことに驚きましたFindByID - 私はまた、私はその明らかな不一致を解決することができると期待している、またはgそれがなぜ実現できないのか、それとも良い考えではないのかをよく理解していますか? :))

答えて

2

例外:それはあなたのジェネリックタイプTのエンティティタイプのリストをサーバーに送り、ExceptUnionをこれらの "定数"オブジェクトのコレクションでSQLで実行することはできません。基本的にはExceptUnionをLINQ to Objectsのメモリに適用する必要があります。つまり、の後にサーバーからのフィルタ処理された結果が実現されています(.ToList()のあと)。コンテキスト内のオブジェクトのリストには、Added州にあるフィルタを2回適用する必要があります。

+0

ありがとうございます!これにより、何が起こっているのかをよりよく理解することができます。 これを読んでいれば、これは私のリポジトリクエリメソッドにとって賢明なアプローチですか?私は、この「オフライン」コレクションに挿入/削除がキューイングされているので、DBSet.Find()がそうしているようにそれらを考慮する必要があると思う傾向がありますが、これを行わない理由があります。 ? – Steven

+1

@Steven: 'Find'はとても特別です。主キーのみを照会します。これはメモリ(第1ステップ)とSQL(第1ステップで何も見つからなければ第2ステップ)で動作します。他のクエリでは、EFがLINQ to Entitiesを使用してクエリを実行し、LINQ to Objectsを使用してユニオンを構築するクエリを実行する必要があることに注意する必要があります。 LINQ to Objectでは(例えば、 'EntityFunctions'を使用する場合)実行できないクエリがあります。または、同じクエリが異なる動作をすることができます(例:文字列検索の大文字と小文字の区別)。 1つのクエリ仕様で両方のクエリを常に実行することは容易でも不可能でもありません。 – Slauma

+1

(続き)おそらく、あなたが望むように実装されていない理由です。これらは、ChangeTrackerでDB照会オブジェクトとオブジェクトの結合を構築する一般的な汎用実装に対する理由です。LTOやLTEに適用した場合や、LTOで動作しない場合でも、フィルタは異なる結果をもたらす可能性があります。クリーンな一般的な実装が可能であることは疑いがあります。あなたは 'ChangeTracker'をまったく問い合わせる必要がないようにしようと思います。本当に必要な場合は、一般的なアプローチを試してはいけません。特定のシナリオでのみ実行し、必要な箇所で特定のクエリを実行してください。 – Slauma

関連する問題