2011-07-14 15 views
5

En ASP.NET MVC 2, utilizando Entity Framework 4, estoy recibiendo este error "Un objeto entidad no puede ser referenciado por varias instancias de IEntityChangeTracker".C# Entity Framework utilizando sólo un ObjectContext por HttpContext

Una búsqueda de SO muestra que probablemente se deba a que tengo instancias diferentes de Entity Framework ObjectContext, cuando debería ser solo una instancia de ObjectContext para cada HttpContext.

tengo este código (escrito mucho antes de que me uní) que aparece para hacer precisamente eso - ObjectContext tener uno para cada HttpContext. Pero me estoy haciendo la excepción "IEntityChangeTracker" con frecuencia por lo que es probable que no funcione como estaba previsto:

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

He examinado este código y parece correcta. Por lo que puedo decir devuelve una instancia de ObjectContext para cada HttpContext. Es el código mal?

Si el código no está mal, ¿por qué si no iba a obtener el "Un objeto entidad no puede ser referenciado por varias instancias de IEntityChangeTracker" excepción?

EDIT: Para mostrar cómo se dispone el 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

están disponiendo que el contexto en el método EndRequest? – Akhil

+0

actualiza para mostrar método de eliminación –

Respuesta

5

Mi conjetura es que usted ha almacenado un objeto en algún lugar de la memoria (muy probablemente el caché HTTP utilizando el modo en proceso, pero también podría ser cualquier caché de instrucciones, tales como un diccionario común), y ahora que has asociado de alguna manera ese objeto con otra cosa, por ejemplo:

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

por lo tanto, un problema si el objeto en caché todavía piensa que está unido a un contexto; No menos importante, probablemente mantengas vivo un gráfico completo.


El código se ve bien (siempre y cuando va a desechar al final de la solicitud), pero esto sería un buen momento para añadir:

private const string EFContextKey = "EF.ObjectContext"; 

y el uso que en lugar de los 5 literales Evita algunos riesgos; p

+0

De hecho, he guardado un objeto en caché (Moneda DefaultCurrency) y después se une al objeto orden (= order.Currency DefaultCurrency) - y eso es exactamente donde se produce la excepción .. Esa es una muy prometedor plomo. Cuando he salvado DefaultCurrency para almacenar en caché es de tipo 'System.Data.Entity.DynamicProxies.Currency_F4008E27DE_etc' lugar de la clase' POCO Entities.Currency'. ¿Qué debo hacer con este objeto para poder almacenarlo de manera segura en el caché y luego agregarlo a otro objeto más adelante, separarlo? –

+1

@JK - complicado; dado que puede haber múltiples hilos tratando de usarlo de una vez, lo mejor que puedo sugerir es escribir un código que lo clone (creando un POCO de vainilla que no esté adjunto al contexto), y * almacenar * un clon (evitar el riesgo de mantener vivo un gráfico) y clonarlo * nuevamente * cada vez que lo recupere. No sé si es posible en EF, pero si fuera L2S, estaría configurando 'DefaultCurrencyId' en lugar de' DefaultCurrency'; se evitarían algunos casos problemáticos. –

+0

Gracias, veré qué puedo hacer allí –

Cuestiones relacionadas