tutorial que net mvc framework first español curso c# .net entity-framework architecture entity-framework-4

c# - que - Entity Framework Contextos de objetos múltiples



mvc entity framework español (4)

Esta pregunta se ha realizado 500 veces diferentes en 50 formas diferentes ... pero aquí está de nuevo, ya que no puedo encontrar la respuesta que estoy buscando:

Estoy usando EF4 con proxies POCO.

R. Tengo un gráfico de los objetos que obtuve de una instancia de ObjectContext. Ese ObjectContext está dispuesto.

B. Tengo un objeto que obtuve de otra instancia de ObjectContext. Ese ObjectContext también ha sido eliminado.

Quiero establecer una propiedad relacionada en un montón de cosas desde A usando la entidad en B ... algo así como

foreach(var itemFromA in collectionFromA) { itemFromA.RelatedProperty = itemFromB; }

Cuando hago eso, obtengo la excepción:

System.InvalidOperationException occurred Message=The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects. Source=System.Data.Entity StackTrace: at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges) at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedEntity, Boolean applyConstraints) at System.Data.Objects.DataClasses.EntityReference`1.set_ReferenceValue(IEntityWrapper value) at System.Data.Objects.DataClasses.EntityReference`1.set_Value(TEntity value) at

Supongo que necesito separar estas entidades de ObjectContexts cuando se deshacen para que lo anterior funcione ... El problema es que separar todas las entidades de mi ObjectContext cuando está disponible parece destruir el gráfico. Si hago algo como:

objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged) .Select(i => i.Entity).OfType<IEntityWithChangeTracker>().ToList() .ForEach(i => objectContext.Detach(i));

Todas las relaciones en el gráfico parecen desarmarse.

¿Cómo puedo resolver este problema?


@Danny Varod tiene razón. Debe usar un ObjectContext para todo el flujo de trabajo. Además, debido a que su flujo de trabajo parece ser una característica lógica que contiene varias ventanas, probablemente también debería usar un solo presentador. Luego, seguiría el enfoque recomendado: contexto único por presentador. Puede llamar a SaveChanges varias veces para que no rompa su lógica.

El origen de este problema es conocido por la deficiencia de los proxies dinámicos generados sobre las entidades POCO combinadas con los métodos Fixup generados por la plantilla POCO T4. Estos proxies aún mantienen referencia al contexto cuando lo desecha. Por eso, piensan que todavía están apegados al contexto y que no pueden vincularse a otro contexto. La única forma de forzarlos a liberar la referencia al contexto es la separación manual. Al mismo tiempo, una vez que se separa una entidad del contexto, se elimina de las entidades asociadas relacionadas porque no puede haber una combinación de entidades adjuntas y separadas en el mismo gráfico.

El problema realmente no aparece en el código que llamas:

itemFromA.RelatedProperty = itemFromB;

pero en la operación inversa activada por el método Fixup:

itemFromB.RelatedAs.Add(itemFromA);

Creo que las formas de resolver esto son:

  • No haga esto y use un contexto único para toda la unidad de trabajo: ese es el supuesto uso.
  • Elimine la propiedad de navegación inversa para que el método Fixup no active ese código.
  • No utilice la plantilla POCO T4 con métodos de reparación o modifique la plantilla T4 para no generarlos.
  • Desactive la carga diferida y la creación de proxy para estas operaciones. Eso eliminará los proxies dinámicos de sus POCO y, por lo tanto, serán independientes en el contexto.

Para desactivar la creación de proxy y la carga lenta, use:

var context = new MyContext(); context.ContextOptions.ProxyCreationEnabled = false;

En realidad, puede tratar de escribir un método personalizado para separar todo el gráfico del objeto, pero como dijo, se le preguntó 500 veces y todavía no he visto una solución de trabajo, excepto la serialización y la deserialización del nuevo gráfico de objetos.


Ok entiendo que el contexto de tu objeto se ha ido hace mucho tiempo.

Pero veámoslo de esta manera, Entity Framework implementa el concepto de unidad de trabajo, en el cual rastrea los cambios que está haciendo en su gráfico de objetos para que pueda generar el SQL correspondiente a los cambios que ha realizado. Sin apego al contexto, no hay forma de que pueda cambiar los cambios.

Si no tienes control sobre el contexto, entonces no creo que haya nada que puedas hacer.

De lo contrario, hay dos opciones,

  1. Mantenga vivo el contexto de su objeto para una vida útil más prolongada, como la sesión del usuario conectado, etc.
  2. Intente regenerar sus clases de proxy utilizando la plantilla de texto de seguimiento automático que habilitará el seguimiento de cambios en estado desconectado.

Pero incluso en caso de auto-seguimiento, es posible que aún tenga pequeños problemas.


No creo que deba separarse para resolver el problema.

Hacemos algo como esto:

public IList<Contact> GetContacts() { using(myContext mc = new mc()) { return mc.Contacts.Where(c => c.City = "New York").ToList(); } } public IList<Sale> GetSales() { using(myContext mc = new mc()) { return mc.Sales.Where(c => c.City = "New York").ToList(); } } public void SaveContact(Contact contact) { using (myContext mc = new myContext()) { mc.Attach(contact); contact.State = EntityState.Modified; mc.SaveChanges(); } } public void Link() { var contacts = GetContacts(); var sales = GetSales(); foreach(var c in contacts) { c.AddSales(sales.Where(s => s.Seller == c.Name)); SaveContact(c); } }

Esto nos permite extraer los datos, pasarlos a otra capa, dejarlos hacer lo que sea que necesiten y luego devolverlos y actualizarlos o eliminarlos. Hacemos todo esto con un contexto separado (uno por método) (uno por solicitud).

Lo importante que debe recordar es que si usa IEnumerables, se trata de ejecución diferida. Lo que significa que en realidad no extraen la información hasta que haces un conteo o iteras sobre ellos. Entonces, si desea usarlo fuera de su contexto, debe hacer una lista ToList () para que se repita y se cree una lista. Entonces puedes trabajar con esa lista.

EDITAR Actualizado para ser más claro, gracias a la entrada de @ Nick.


Creo que tienes algunas opciones diferentes aquí, 2 de ellas son:

  1. Deje vivo el contexto hasta que haya terminado con el proceso, use solo 1 contexto, no 2.

  2. a. Antes de deshacerse del contexto n. ° 1, cree un clon profundo del gráfico, utilizando BinaryStreamer o una herramienta como ValueInjecter o AutoMapper.

    segundo. Merge los cambios del contexto # 2 en el gráfico clonado.

    do. Al guardar, combine los cambios del gráfico clonado en el gráfico creado por el nuevo ObjectContext.

Para futuras referencias, este enlace de blogs de MSDN puede ayudarlo a decidir qué hacer cuando: http://blogs.msdn.com/b/dsimmons/archive/2008/02/17/context-lifetimes-dispose-or-reuse. aspx