2011-07-14 80 views
5

在ASP.NET MVC 2中,使用實體框架4時,出現「IEntityChangeTracker的多個實例無法引用實體對象」的錯誤。每個HttpContext只使用一個ObjectContext的C#實體框架

SO的搜索表明它可能是因爲我有不同的實體框架ObjectContext的實例,它應該只是每個HttpContext的一個ObjectContext實例。

我有這樣的代碼(寫入很久之前我加入),似乎做到這一點 - 每個HttpContext有一個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返回一個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(); 
    } 
} 
+0

你在EndRequest方法中處理上下文嗎? – Akhil

+0

已更新爲顯示處置方法 –

回答

5

我的猜測是,你在什麼地方存儲對象在內存中(最有可能使用過程中的模式HTTP緩存,但也可能是任何手動緩存,例如共享字典),現在你已經有了某種聯繫別的東西該對象,例如:

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個文字。避免一些風險; p

+0

其實我已經將一個對象存儲在緩存(貨幣DefaultCurrency)中,然後將其附加到訂單對象(order.Currency = DefaultCurrency) - 這正是拋出異常的地方..這是一個非常很有前途。當我保存DefaultCurrency緩存時,它的類型是'System.Data.Entity.DynamicProxies.Currency_F4008E27DE_etc',而不是POCO類'Entities.Currency'。我需要如何處理這個對象,才能夠安全地將它存儲在緩存中,然後再將它添加到另一個對象中,然後將它分離出來? –

+1

@JK - 棘手;因爲可能有多個線程一次嘗試使用它,所以我可以建議的最好的方法是編寫一些克隆它的代碼(創建一個未附加到上下文的vanilla POCO),並存儲一個克隆(避免保持圖形存活的風險),並且每次將它取出時再次克隆*。我不知道在EF中是否可能,但如果這是L2S,我會設置DefaultCurrencyId而不是DefaultCurrency,這樣可以避免一些問題。 –

+0

謝謝,我會看看我能在那裏做些什麼 –

相關問題