c# asp.net asp.net-mvc-3 entity-framework entity-framework-4.1

c# - Adjuntar y separar entidades del contexto correctamente en EF4.1



asp.net asp.net-mvc-3 (2)

Estoy tratando de implementar un mecanismo de almacenamiento en caché para las entidades. Y para usar las entidades correctamente y sin problemas con el almacenamiento en caché, necesito separar la entidad del contexto actual antes de ponerla en una memoria caché y adjuntarla de nuevo al contexto nuevo cuando la obtengo de la memoria caché. (Mi vida útil del contexto es por solicitud de http)

Los requisitos son que

  1. Todas las propiedades de navegación que están asociadas con él (que ya he rellenado) no deben eliminarse cuando la entidad se separa.
  2. Puedo actualizar los elementos almacenados en caché si lo deseo (por lo tanto, adjuntarlos al nuevo contexto es importante).

Este es mi intento de crear una clase EntityCache - (ServerCache aquí es mi clase envoltura que empuja el objeto a la memoria caché ASP.NET)

public static class EntityCache { private static DbContext context { get { return (DbContext)HttpContext.Current.Items[ObjectKeys.ContextRequestItemKey]; } } private static void Detach(object entity) { var trackedEntity = entity as IEntityWithChangeTracker; trackedEntity.SetChangeTracker(null); ((IObjectContextAdapter)context).ObjectContext.Detach(entity); } private static void Attach(object entity) { ((IObjectContextAdapter)context).ObjectContext.Attach((IEntityWithKey)entity); } public static void Remove(string key) { ServerCache.Remove(key); } public static object Get(string key) { object output = ServerCache.Get(key); if (output != null) Attach(output); return output; } public static void ShortCache(String key, object data) { if (data != null) { Detach(data); ServerCache.ShortCache(key, data); } } public static void LongCache(String key, object data) { if (data != null) { Detach(data); ServerCache.LongCache(key, data); } } }

Cuando pongo una entidad en el caché es de tipo DynamicProxy y NO la clase real.

La conexión no funciona en absoluto: recibo una excepción por la que no puedo colocar un objeto que sea del tipo Dynamic_ {blahblah} en IEntityWithKey.

Acabo de ver estos ejemplos de adjuntar y separar en línea y los probé. Estoy abierto a cualquier nueva implementación de los métodos de Adjuntar / Separar aquí.

Gracias.

Siguiente pregunta -

context.Entry(entity).State = EntityState.Detached;

Funciona, pero hace que todas las propiedades de navegación que están cargadas sean NULL, ¿cómo hacemos que mantenga las propiedades de navegación y NO las reemplace (o pierda) con NULL cuando nos separamos del contexto?


A su pregunta de seguimiento:

... cómo hacemos para mantener las propiedades de navegación y NO reemplazarlas (o perderlas) con NULL cuando nos separamos del contexto ...

Creo que no es posible separar un gráfico de objeto del contexto mientras se mantienen sus propiedades de navegación. Desde MSDN :

En una asociación independiente, la información de relación no se mantiene para un objeto separado.

Aunque esta declaración es sobre asociaciones independientes, no significa que las propiedades de navegación se mantengan en asociación de clave externa (relaciones que exponen una propiedad de clave externa en el modelo). Sí, la "información de relación" se mantiene porque las propiedades de la clave foránea (que son propiedades escalares) estarán activas y contendrán el valor correcto de la clave foránea después de la separación. Pero las propiedades de navegación correspondientes seguirán siendo null para las propiedades de referencia o, para las colecciones de navegación, la referencia se eliminará de la colección.

Creo que la única forma de separar un gráfico de objeto completo de un contexto es disponer el contexto por completo o crear una copia del gráfico antes de comenzar a separar el gráfico original. Crear una copia requeriría escribir métodos de Clone que copien todas las propiedades y naveguen a través del gráfico o utilizando un "truco" como this que serializa el gráfico en una secuencia binaria y luego lo deserializa a nuevos objetos. Para esto las entidades tendrían que ser serializables. También los ciclos de referencia (que a menudo tenemos al usar propiedades de navegación bidireccionales entre entidades) pueden causar problemas. (También preste atención si sus objetos son proxies que contienen referencias a los objetos internos de EF y que probablemente no desee copiar, serializar y deserializar).

En este aspecto, Detach no es la contrapartida de Attach porque se comporta de manera muy diferente: Attach adjunta todo el gráfico de objetos y mantiene las propiedades de navegación. Detach solo separa entidades individuales sin los objetos relacionados y destruye las propiedades de navegación. Desde la misma página enlazada arriba:

La separación solo afecta al objeto específico pasado al método. Si el objeto que se está separando tiene objetos relacionados en el contexto del objeto, esos objetos no se separan.

Podría imaginar que esta es la razón principal por la que la API DbContext no tiene un método de DbContext explícito (en contraste con ObjectContext ): la separación se considera como una característica avanzada que no se comporta como se podría esperar.

MSDN menciona como la única razón para separar un objeto del contexto "para conservar recursos" (nuevamente el artículo anterior):

En las aplicaciones de Entity Framework, puede separar objetos del contexto del objeto. Puede separar objetos para conservar recursos, ya que la ejecución de consultas repetidas en el mismo contexto de objeto aumenta los requisitos de memoria del contexto de objeto.

Creo que este método simplemente no está preparado y diseñado para trabajar con los objetos después de que se hayan separado del contexto. Su principal objetivo es liberarlos para la recolección inmediata de basura.


IEntityWithKey es una interfaz para otros tipos de entidades. Es para entidades "grandes". Por ejemplo EntityObject implementa esta interfaz. Estas entidades no se consideran como POCO y no son compatibles con la API de DbContext .

Si desea utilizar IEntityWithKey sus clases deben implementarlo, no es algo que suceda automáticamente.

La correcta DbContext con DbContext API debería ser:

dbContext.Set(typeof(entity)).Attach(entity);

y con suerte esto debería funcionar también:

dbContext.Entry(entity).State = EntityState.Unchanged;

La DbContext correcta con la API DbContext debe ser:

dbContext.Entry(entity).State = EntityState.Detached;

También es mejor para usted métodos genéricos en lugar de object .