5

ASP.NET MVC 2で、Entity Framework 4を使用すると、「エンティティオブジェクトをIEntityChangeTrackerの複数のインスタンスで参照できません」というエラーが発生します。

SOを検索すると、HttpContextごとに1つのObjectContextインスタンスのみである必要があるのに、EntityFrameworkObjectContextのインスタンスが異なることが原因である可能性があります。

私はまさにそれをしているように見えるこのコード(私が参加するずっと前に書かれた)を持っています-すべてのHttpContextに対して1つのObjectContextを持っています。しかし、「IEntityChangeTracker」例外が頻繁に発生するため、意図したとおりに機能していない可能性があります。

// in ObjectContextManager.cs
public const string ConnectionString = "name=MyAppEntities";
public const string ContainerName = "MyAppEntities";

public static ObjectContext GetObjectContext()
{
    ObjectContext objectContext = GetCurrentObjectContext();
    if (objectContext == null) // create and store the object context
    {   
        objectContext = new ObjectContext(ConnectionString, ContainerName);     
        objectContext.ContextOptions.LazyLoadingEnabled = true;    
        StoreCurrentObjectContext(objectContext);
    }
    return objectContext;
}

private static void StoreCurrentObjectContext(ObjectContext objectContext)
{
    if (HttpContext.Current.Items.Contains("EF.ObjectContext"))
        HttpContext.Current.Items["EF.ObjectContext"] = objectContext;
    else
        HttpContext.Current.Items.Add("EF.ObjectContext", objectContext);
}

private static ObjectContext GetCurrentObjectContext()
{
    ObjectContext objectContext = null;
    if (HttpContext.Current.Items.Contains("EF.ObjectContext")
        objectContext = (ObjectContext)HttpContext.Current.Items["EF.ObjectContext"];
    return objectContext;
}

私はこのコードを調べましたが、正しいように見えます。HttpContextごとに1つのObjectContextインスタンスを返すように指示できる限り、これは実行されます。コードは間違っていますか?

コードが間違っていない場合、「エンティティオブジェクトはIEntityChangeTrackerの複数のインスタンスで参照できません」という例外が発生するのはなぜですか?

編集:ObjectContextがどのように破棄されるかを示すには:

// in HttpRequestModule.cs
private void Application_EndRequest(object source, EventArgs e)
{
    ServiceLocator.Current.GetInstance<IRepositoryContext>().Terminate();
}

// in RepositoryContext.cs
public void Terminate() 
{
    ObjectContextManager.RemoveCurrentObjectContext();
}

// in ObjectContextManager.cs
public static void RemoveCurrentObjectContext()
{
    ObjectContext objectContext = GetCurrentObjectContext();
    if (objectContext != null)
    {
        HttpContext.Current.Items.Remove("EF.ObjectContext");
        objectContext.Dispose();
    }
}
4

1 に答える 1

5

私の推測では、オブジェクトをメモリのどこかに保存し(ほとんどの場合、インプロセスモードを使用するhttpキャッシュですが、共有ディクショナリなどの手動キャッシュでもかまいません)、そのオブジェクトを何かに関連付けました。それ以外の場合、たとえば:

newOrder.OwnerUser = currentUser; // <== let's say currentUser came from cache
                                  // and newOrder was on your new entity context

したがって、キャッシュされたオブジェクトがまだコンテキストにアタッチされていると見なす場合は問題が発生します。特に、グラフ全体を誤って存続させている可能性があります。


コードは(リクエストの最後に破棄している限り)問題ないように見えますが、次のように追加するのがよいでしょう。

private const string EFContextKey = "EF.ObjectContext";

5つのリテラルの代わりにそれを使用します。いくつかのリスクを回避します;p

于 2011-07-14T05:34:56.737 に答える