2011-07-14 7 views
5

ASP.NET MVC 2では、Entity Framework 4を使用して、「エンティティオブジェクトはIEntityChangeTrackerの複数のインスタンスで参照できません」というエラーが表示されます。HttpContextごとにObjectContextを1つだけ使用するEntity Framework

SOの検索では、Entity Framework ObjectContextのインスタンスがそれぞれ異なるため、おそらくHttpContextごとに1つのObjectContextインスタンスにする必要があると考えられます。

すべてのHttpContextに対して1つのObjectContextを持っています。

// 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; 
} 

を、私はこのコードを検討してきたし、それが正しいになります。それはおそらく意図したとおりに動作していないので、しかし、私は頻繁に「IEntityChangeTracker」の例外を取得しています。各HttpContextに対して1つのObjectContextインスタンスを返すことができます。コードが間違っていますか?

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

EDIT:

// 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(); 
    } 
} 
+0

EndRequestメソッドでコンテキストを破棄していますか? – Akhil

+0

処分方法を表示するように更新されました –

答えて

5

私の推測では、インプロセスモードを使用して、最も可能性の高いHTTPキャッシュ(あなたはメモリのどこかにオブジェクトを格納してきたということですが、また次のようになります。ObjectContextには配置されている方法を表示するにはそのような共有辞書として手動キャッシュ)、そして今は何とか例えば、何か他のもので、そのオブジェクトを関連付けた:

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

、問題をキャッシュされたオブジェクトはまだそれがコンテキストに接続されていると考えるならば、おそらく、おそらく全体のグラフを誤って生き残っていると思います。


(あなたはリクエストの終了時に、それを配置している限り)コードはOKに見えますが、これは追加するには良い時間のようになります。

private const string EFContextKey = "EF.ObjectContext"; 

をし、代わりにそれを使います5リテラル。いくつかのリスクは避けてください;

+0

実際には、オブジェクトをキャッシュ(通貨DefaultCurrency)に格納してから注文オブジェクト(order.Currency = DefaultCurrency)にアタッチしました。これは例外がスローされる場所です。有望なリード。 DefaultCurrencyをキャッシュに保存すると、POCOクラスの 'Entities.Currency'の代わりに' System.Data.Entity.DynamicProxies.Currency_F4008E27DE_etc'型です。このオブジェクトをキャッシュに安全に保管し、後で別のオブジェクトに追加できるようにするには、このオブジェクトで何を行う必要がありますか? –

+1

@JK - トリッキー;一度に複数のスレッドを使用しようとしている可能性があるので、私が提案できる最も良い方法は、クローンを作成するコードを書いて(コンテキストに添付されていないバニラPOCOを作成し)、*グラフを生きたままにするリスク)、それを取り出すたびに再度*複製してください。私はEFで可能かどうか分かりませんが、L2Sなら 'DefaultCurrency'ではなく' DefaultCurrencyId'を設定しています - いくつかの問題が回避されています。 –

+0

ありがとう私は私がそこで何ができるかを見ます –

関連する問題