¿Es posible verificar si un objeto ya está adjunto a un contexto de datos en Entity Framework?

Recibo el siguiente error al intentar adjuntar un objeto que ya está adjunto a un contexto dado a través de context.AttachTo(...) :

Ya existe un objeto con la misma clave en ObjectStateManager. ObjectStateManager no puede rastrear múltiples objetos con la misma clave.

¿Hay alguna forma de lograr algo como:

context.IsAttachedTo(...)

¡Aclamaciones!

Editar:

El método de extensión que describió Jason está cerca, pero no funciona para mi situación.

Estoy tratando de hacer un trabajo utilizando el método descrito en la respuesta a otra pregunta:

¿Cómo elimino una o más filas de mi tabla usando Linq para entidades * sin * recuperar las filas primero?

Mi código se parece un poco a esto:

 var user = new User() { Id = 1 }; context.AttachTo("Users", user); comment.User = user; context.SaveChanges(); 

Esto funciona bien, excepto cuando hago otra cosa para ese usuario donde uso el mismo método y trato de adjuntar un objeto User ficticio. Esto falla porque he adjuntado previamente ese objeto de usuario ficticio. ¿Cómo puedo verificar esto?

Aquí es a lo que terminé, que funciona muy bien:

 public static void AttachToOrGet(this ObjectContext context, string entitySetName, ref T entity) where T : IEntityWithKey { ObjectStateEntry entry; // Track whether we need to perform an attach bool attach = false; if ( context.ObjectStateManager.TryGetObjectStateEntry ( context.CreateEntityKey(entitySetName, entity), out entry ) ) { // Re-attach if necessary attach = entry.State == EntityState.Detached; // Get the discovered entity to the ref entity = (T)entry.Entity; } else { // Attach for the first time attach = true; } if (attach) context.AttachTo(entitySetName, entity); } 

Puedes llamarlo de la siguiente manera:

 User user = new User() { Id = 1 }; II.AttachToOrGet("Users", ref user); 

Esto funciona muy bien porque es como el context.AttachTo(...) excepto que puede usar el truco de identificación que he citado anteriormente cada vez. Usted termina con el objeto previamente adjuntado o con su propio objeto adjunto. Llamar a CreateEntityKey sobre el contexto asegura que sea agradable y genérico, y funcionará incluso con claves compuestas sin encoding adicional (¡porque EF ya puede hacer eso por nosotros!).

Un enfoque más simple es:

  bool isDetached = context.Entry(user).State == EntityState.Detached; if (isDetached) context.Users.Attach(user); 

Pruebe este método de extensión (esto no se ha probado y está fuera de línea):

 public static bool IsAttachedTo(this ObjectContext context, object entity) { if(entity == null) { throw new ArgumentNullException("entity"); } ObjectStateEntry entry; if(context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry)) { return (entry.State != EntityState.Detached); } return false; } 

Dada la situación que describes en tu edición, es posible que necesites usar la siguiente sobrecarga que acepta una EntityKey lugar de un objeto:

 public static bool IsAttachedTo(this ObjectContext, EntityKey key) { if(key == null) { throw new ArgumentNullException("key"); } ObjectStateEntry entry; if(context.ObjectStateManager.TryGetObjectStateEntry(key, out entry)) { return (entry.State != EntityState.Detached); } return false; } 

Para construir una EntityKey en su situación, use lo siguiente como una guía:

 EntityKey key = new EntityKey("MyEntities.User", "Id", 1); 

Puede obtener EntityKey de una instancia de User existente utilizando la propiedad User.EntityKey (desde la interfaz IEntityWithKey ).

Usando la clave de entidad del objeto que está tratando de verificar:

 var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey"); if (entry.State == EntityState.Detached) { // Do Something } 

Amabilidad,

Dan

Esto no responde directamente la pregunta de OP, pero así es como resolví la mía.

Esto es para aquellos que están usando DbContext lugar de ObjectContext .

  public TEntity Retrieve(object primaryKey) { return DbSet.Find(primaryKey); } 

Método DbSet.Find :

Encuentra una entidad con los valores de clave primaria dados. Si existe una entidad con los valores de clave primaria dados en el contexto, se devuelve inmediatamente sin realizar una solicitud a la tienda. De lo contrario, se realiza una solicitud a la tienda para una entidad con los valores de clave primaria dados y esta entidad, si se encuentra, se adjunta al contexto y se devuelve. Si no se encuentra ninguna entidad en el contexto o la tienda, se devuelve null.

Básicamente, devuelve el objeto adjunto de la primaryKey dada, primaryKey lo que solo necesita aplicar los cambios en el objeto devuelto para mantener la instancia correcta.