it-swarm-ja.tech

オブジェクトが既にEntity Frameworkのデータコンテキストに接続されているかどうかを確認することはできますか?

context.AttachTo(...)を介して特定のコンテキストに既にアタッチされているオブジェクトをアタッチしようとすると、次のエラーが表示されます。

同じキーを持つオブジェクトが既にObjectStateManagerに存在します。 ObjectStateManagerは、同じキーを持つ複数のオブジェクトを追跡できません。

以下のラインに沿って何かを達成する方法はありますか?

context.IsAttachedTo(...)

乾杯!

編集:

Jasonが説明した拡張方法は似ていますが、私の状況では機能しません。

私は別の質問への答えに概説されている方法を使用していくつかの仕事をしようとしています:

最初に行を取得せずにLinq to Entitiesを使用してテーブルから1つ以上の行を削除するにはどうすればよいですか?

私のコードは次のようになります。

var user = new User() { Id = 1 };
context.AttachTo("Users", user);
comment.User = user;
context.SaveChanges();

これは、同じメソッドを使用してダミーのUserオブジェクトをアタッチしようとするユーザーに対して別の操作を行う場合を除き、正常に機能します。ダミーのユーザーオブジェクトを以前に添付したため、これは失敗します。これを確認するにはどうすればよいですか?

82
joshcomley

これが私が結んだもので、非常にうまく機能します:

_public static void AttachToOrGet<T>(this ObjectContext context, string entitySetName, ref T entity)
    where T : IEntityWithKey
{
    ObjectStateEntry entry;
    // Track whether we need to perform an attach
    bool attach = false;
    if (
        context.ObjectStateManager.TryGetObjectStateEntry
            (
                context.CreateEntityKey(entitySetName, entity),
                out entry
            )
        )
    {
        // Re-attach if necessary
        attach = entry.State == EntityState.Detached;
        // Get the discovered entity to the ref
        entity = (T)entry.Entity;
    }
    else
    {
        // Attach for the first time
        attach = true;
    }
    if (attach)
        context.AttachTo(entitySetName, entity);
}
_

次のように呼び出すことができます。

_User user = new User() { Id = 1 };
II.AttachToOrGet<Users>("Users", ref user);
_

これは、上で引用したIDトリックを毎回使用できることを除いて、context.AttachTo(...)に似ているため、非常にうまく機能します。最終的には、以前にアタッチされたオブジェクトまたはアタッチされている独自のオブジェクトのいずれかになります。コンテキストでCreateEntityKeyを呼び出すと、それがニースで一般的であり、さらにコーディングすることなく複合キーでも動作します(EFは既にそれを行っているためです!)。

56
joshcomley

より簡単なアプローチは次のとおりです。

 bool isDetached = context.Entry(user).State == EntityState.Detached;
 if (isDetached)
     context.Users.Attach(user);
46
Mosh

この拡張方法を試してください(これはテストされておらず、すぐに使用できます):

public static bool IsAttachedTo(this ObjectContext context, object entity) {
    if(entity == null) {
        throw new ArgumentNullException("entity");
    }
    ObjectStateEntry entry;
    if(context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry)) {
        return (entry.State != EntityState.Detached);
    }
    return false;
}

編集で記述する状況を考えると、オブジェクトの代わりにEntityKeyを受け入れる次のオーバーロードを使用する必要がある場合があります。

public static bool IsAttachedTo(this ObjectContext, EntityKey key) {
    if(key == null) {
        throw new ArgumentNullException("key");
    }
    ObjectStateEntry entry;
    if(context.ObjectStateManager.TryGetObjectStateEntry(key, out entry)) {
        return (entry.State != EntityState.Detached);
    }
    return false;
}

状況に応じてEntityKeyを作成するには、以下をガイドラインとして使用します。

EntityKey key = new EntityKey("MyEntities.User", "Id", 1);

プロパティUser.EntityKeyを使用して(インターフェイスEntityKeyから)Userの既存のインスタンスからIEntityWithKeyを取得できます。

18
jason

確認しようとしているオブジェクトのエンティティキーを使用して:

var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey");
if (entry.State == EntityState.Detached)
{
  // Do Something
}

親切、

ダン

6
Daniel Elliott

これはOPの質問に直接答えるわけではありませんが、これが私の解決方法です。

これは、DbContextの代わりにObjectContextを使用している人向けです。

    public TEntity Retrieve(object primaryKey)
    {
        return DbSet.Find(primaryKey);
    }

DbSet.Findメソッド

指定された主キー値を持つエンティティを検索します。指定された主キー値を持つエンティティがコンテキストに存在する場合、ストアにリクエストを送信せずにすぐに返されます。それ以外の場合、指定されたプライマリキー値を持つエンティティのストアに対してリクエストが行われ、このエンティティが見つかった場合はコンテキストに添付されて返されます。コンテキストまたはストアでエンティティが見つからない場合、nullが返されます。

基本的に、指定されたprimaryKeyのアタッチされたオブジェクトを返すので、正しいインスタンスを保持するには、返されたオブジェクトに変更を適用するだけです。

0
Lawrence