Estoy recibiendo el siguiente error al intentar adjuntar un objeto que ya está conectado a un contexto determinado a través de context.AttachTo(...):

Un objeto con la misma clave que ya existe en el ObjectStateManager. El ObjectStateManager puede realizar un seguimiento de múltiples objetos con la misma clave.

Hay una manera de lograr algo a lo largo de las líneas de:

context.IsAttachedTo(...)

Saludos!

Editar:

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

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

¿Cómo puedo eliminar una o varias filas de la tabla usando Linq to entities *sin* recuperar las filas primero?

Mi código 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 tengo que hacer algo más para que el usuario donde puedo usar el mismo método y tratar de fijar un maniquí User objeto. Esta falla porque he adjuntado anteriormente que ficticio objeto de usuario. ¿Cómo puedo comprobar esto?

InformationsquelleAutor joshcomley | 2009-11-11

5 Comentarios

  1. 56

    He aquí lo que terminó con, que funciona muy bien:

    public static void AttachToOrGet<T>(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);
    }

    Se le puede llamar de la siguiente manera:

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

    Esto funciona muy bien porque es como context.AttachTo(...) excepto que usted puede utilizar el ID de truco que he citado anteriormente cada vez. Se termina con el objeto conectado previamente o en su propio objeto que se adjunta. Llamar CreateEntityKey en el contexto hace que sea agradable y genérico y funcionará incluso con claves compuestas con no más de codificación (como EF que podemos hacer ya que para nosotros!).

    • Yo estaba teniendo un problema similar, y esto acaba de resolver el mío genial, saludos! +1
    • Sería aún mejor cuando el parámetro de cadena es reemplazado por un selector de función para la recolección de la entidad a la que pertenece.
    • Alguna idea de por qué (T)entry.Entity a veces devuelve null?
    • Muy bonito. Gracias
    • No puedo calcular lo que debe ser la configuración de mi entitySetName a. Sigo recibiendo una excepción. Estoy realmente frustrado porque todo lo que quiero hacer es eliminar un usuario yo no quiero tener que lidiar con tanto ocultos no-sentido soplando mi aplicación.
    • Exactamente mi problema, excepto que yo uso la Base de datos del primer enfoque. ¿Alguien sabe cómo hacer esto para la primera Base de datos?
    • Estoy utilizando la base de datos primero así y funciona bien. Se han especificado como «EntityContainer.EntitySet» para el entitySetName? (Inserte su nombre en la cadena)
    • si T ya está IEntityWithKey, no puede usted sólo tiene que utilizar su entity.EntityKey de la propiedad en lugar de reconstruir o necesidad de adivinar proporcionar la EntitySetName?
    • Alguna manera de hacer esto de forma genérica en la que no sabemos el tipo o el nombre del conjunto antes de tiempo?

  2. 46

    Un enfoque más sencillo es:

     bool isDetached = context.Entry(user).State == EntityState.Detached;
     if (isDetached)
         context.Users.Attach(user);
    • Esto funcionó para mí, sólo he tenido que usar la «EntityState.Unifamiliar» en lugar de «independiente»…
    • Gracias por el comentario! He editado la respuesta 🙂
    • Hmm intentado la solución, pero para mí isDetached es cierto, pero sigue el mismo error cuando intento Adjuntar la entrada de contexto
    • Excelente appraoch. Incluso se trabajó con mi Genérica Repositorio.
    • Hace poco me enteré de la razón Mosh de la verificación no siempre es suficiente para evitar el error, es que .Include()‘ed propiedades de navegación son también intentó ser conectado al llamar .Attach o conjuntos de sus EntityState a EntityState.Unchanged – y tendrán un conflicto si alguna de las entidades a que se refieren a la misma entidad. No he de averiguar cómo sólo fijar la base de la entidad, por lo que tuve que rediseñar el proyecto un poco, para el uso independiente de los contextos para cada «transacción comercial», como la que fue diseñado. Voy a esta nota para futuros proyectos.
  3. 18

    Probar este método de extensión (esto no está probado y fuera de la manga):

    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 usted describe en su edición, puede que tenga que utilizar la siguiente sobrecarga que acepta un EntityKey en 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 un EntityKey en su situación, utilice el siguiente como guía:

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

    Usted puede conseguir el EntityKey de una instancia existente de User mediante el uso de la propiedad User.EntityKey (desde la interfaz de IEntityWithKey).

    • Esto es muy bueno, pero no me funciona en mi situación… voy a actualizar a la pregunta con detalles. p.s. desea bool no booleano, y la estática, pero aparte de que es bastante impresionante método de extensión!
    • Creo que se puede abordar mediante una sobrecarga de TryGetObjectStateEntry que acepta un EntityKey en lugar de un object. He modificado en consecuencia. Quisiera saber si esto no ayuda, y vamos a volver a la mesa de dibujo.
    • Ah, acabo de ver esto – yo estaba trabajando en una solución expuesta en una respuesta que acaba de publicar. +1 por tu ayuda y consejos!!
    • Alguna idea de por qué estoy recibiendo un error, el detalles es aquí stackoverflow.com/questions/6653050/…
  4. 6

    El uso de la clave de entidad de que el objeto que está tratando de comprobar:

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

    Bondad,

    Dan

  5. 0

    Este no responden directamente OPs pregunta, pero esta es la forma en que resolvió el mío.

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

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

    DbSet.Encontrar El Método:

    Encuentra una entidad con los valores de clave principal. Si una entidad con
    el dado de valores de clave principal se da en el contexto, entonces es
    regresó de inmediato, sin hacer un pedido a la tienda. De lo contrario,
    se realiza una solicitud a la tienda a por una entidad con el principal dada
    los valores de la clave y esta entidad, si se encuentra, se adjunta el contexto y
    devuelto. Si ninguna entidad se encuentra en el contexto o en la tienda, entonces null
    se devuelve.

    Básicamente, se devuelve el objeto adjunto de la primaryKey por lo que sólo necesita para aplicar los cambios en el objeto devuelto a mantener el derecho de instancia.

Dejar respuesta

Please enter your comment!
Please enter your name here