web-dev-qa-db-ja.com

Entity Frameworkにエンティティが存在するかどうかを確認する一般的な方法は?

Entity Frameworkにオブジェクトが存在するかどうかを確認する最良の方法?

DbSet内のエンティティをチェックする一般的な方法を探しています。機能しないこのようなもの:

private DbContext DbContext { get; set; }

private DbSet<T> DbSet { get; set; }

public Boolean Exists(T entity) {
    return ((from item in this.DbSet
             where item == entity
             select item).Count() > 0);
}

この線 where item == entityはLINQ to SQLで機能しますが、明らかにLINQ to Entitiesでは機能しません。エンティティは異なるキーを持っている可能性があるため、既知のキーを持つ共通の抽象からすべてを比較のために継承させることはできません。

これはできますが、検証プロセスとして例外をキャッチするパフォーマンスが心配です エンティティが切り離されている限りOriginalValuesプロパティを取得できないため、これも機能しません。

public Boolean Exists(T entity) {
    try {
        var current = this.DbContext.Entry(entity).OriginalValues;
        // Won't reach this line if the entity isn't in the database yet
        return true;
    }
    catch (Exception ex) {
        return false;
    }
}
57
Yuck

エンティティがコンテキストによってロードされたかどうかを確認する一般的な方法、またはエンティティが存在する場合にデータベースを照会する一般的な方法が必要ですか?

前者の場合:

public bool Exists<T>(T entity) where T: class
{
    return this.Set<T>().Local.Any(e => e == entity);
}

後者の場合に使用します(読み込まれたエンティティもチェックします):

public bool Exists<T>(params object[] keys)
{
    return (this.Set<T>().Find(keys) != null);
}

編集:

EFコードは最初にこの種の情報にアクセスすることを想定していませんが、エンティティキーの名前を取得することは可能です。私はそのような何かがうまくいくと思う:

var objContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var objSet = objContext.CreateObjectSet<T>();
var keyNames = objSet.EntitySet.ElementType.KeyMembers.Select(m => m.Name);

しかし、これはすべて意味がありません。ジェネリックアプローチが必要ですが、エンティティはジェネリックアプローチを可能にするために必要な情報を共有しません。今、あなたはキー値さえ知らないと言います。この「汎用」アプローチを使用するには、リフレクションと式ツリーの手動構築が必要です。

84
Ladislav Mrnka

私を正しい方向に導いてくれた@Ladislavに感謝します。汎用Exists()メソッドのコードは次のとおりです。

これはリフレクションを必要とせず、非常によく機能するように見えることに注意してください。ワクワクしていない唯一のことは、TryGetObjectByKey()には見つかったエンティティをアタッチする副作用があるということです。 Exists()に意図しない結果を与えたくないので、エンティティが見つかった場合は切り離す必要があります。

public Boolean Exists(T entity) {
    var objContext = ((IObjectContextAdapter)this.DbContext).ObjectContext;
    var objSet = objContext.CreateObjectSet<T>();
    var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);

    Object foundEntity;
    var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity);
    // TryGetObjectByKey attaches a found entity
    // Detach it here to prevent side-effects
    if (exists) {
        objContext.Detach(foundEntity);
    }

    return (exists);
}
21
Yuck