El objeto no se puede eliminar porque no se encontró en ObjectStateManager

114

Recibo este error "El objeto no se puede eliminar porque no se encontró en ObjectStateManager".

Mi codigo es:

    protected MyEntities sqlEntities;

    public virtual void Delete(TEntity entity)
    {
        System.Type t = typeof(TEntity);
        sqlEntities.DeleteObject(entity);
        sqlEntities.SaveChanges();
    }
Sami
fuente
5
Lo sentimos, hubo un problema en el código por el que se usaron diferentes objetos de contexto de datos para recuperar y eliminar registros.
Sami
Tuve un error como este: var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);estaba tratando de crear una entidad simulada con su PK configurado correctamente, con la esperanza de que Entity Framework llamara a DeleteObject basado en PK
C. Tewalt

Respuestas:

156

Significa que la entidad no está adjunta (no fue cargada por la misma instancia de contexto). Prueba esto:

protected MyEntities sqlEntities;

public virtual void Delete(TEntity entity)
{
    sqlEntities.Attach(entity);
    sqlEntities.DeleteObject(entity);
    sqlEntities.SaveChanges();
}
Ladislav Mrnka
fuente
1
Gracias Ladislav. Esto me ayudó cuando tuve dos contextos al eliminar datos secundarios de un padre, que se llamó desde un contexto diferente, fuera de un TransactionScope. Moví la llamada principal dentro del alcance y el mismo contexto y mi problema se resolvió.
dan richardson
1
@Ladislav: Si utilizo .Attach, recibo un error diferente: "Un objeto de entidad no puede ser referenciado por varias instancias de IEntityChangeTracker". ¿Significa que ya hay otras instancias de objetos vivas que impiden la eliminación?
Matt
2
@Matt: No, significa que su objeto ya está adjunto a otro contexto. No se puede unir a dos al mismo tiempo. Debes usar el contexto original para eliminar la entidad.
Ladislav Mrnka
@Ladislav: Gracias, eso me ayudó a buscar más. Encontré esta pregunta que parece responder cómo abordarla: ¿Es posible verificar si un objeto ya está adjunto a un contexto de datos en Entity Framework? . Tienes razón, este parece ser el problema en mi caso. ¡Gracias por la rápida respuesta!
Matt
Gracias por el recordatorio, lo adjunté cuando recién estaba actualizando un registro, pero no cuando estaba borrando un registro.
pinmonkeyiii
60

Solo una pequeña aclaración sobre la respuesta de Ladislav Mrnka (que debería ser la respuesta aceptada).

Si como yo, tienes un código en un formato como este:

using (var context = new MyDataContext())
{
    context.MyTableEntity.Remove(EntytyToRemove);
    var nrOfObjectsChanged = context.SaveChanges();
}

... entonces esto es lo que quieres hacer:

using (var context = new MyDataContext())
{
    // Note: Attatch to the entity:
    context.MyTableEntity.Attach(EntityToRemove);

    context.MyTableEntity.Remove(EntityToRemove);
    var nrOfObjectsChanged = context.SaveChanges();
}

Quizás esto parezca obvio, pero al principio no me quedó claro que es necesario especificar la entidad a la que unirse, y no solo el contexto .

Kjartan
fuente
1
Utilizo este enfoque y recibo una excepción: "La declaración de actualización, inserción o eliminación de la tienda afectó a un número inesperado de filas (0). Es posible que las entidades se hayan modificado o eliminado desde que se cargaron las entidades. Actualizar las entradas de ObjectStateManager".
kat1330
11

Solo para corregir la explicación de Kjartans:

Yo tenía:

public Project DeleteProject(int id)
    {
        using (var context = new Context())
        {
            var p = GetProject(id);
            context.Projects.Remove(p);
            context.SaveChanges();
            return p;
        }
    }

El problema es que usé mi propio método (GetProject ()) para obtener la entidad (por lo tanto, usé otro contexto para cargar la entidad):

public Project GetProject(int id)
    {
        using (var context = new Context())
        {
            var project = context.Projects
                .Include(p => p.Reports.Select(q => q.Issues.Select(r => r.Profession)))
                .Include(p => p.Reports.Select(q => q.Issues.Select(r => r.Room)))
                .SingleOrDefault(x => x.Id == id);
            return project;      
        }
    }

Una solución podría ser adjuntar la entidad cargada como dice Kjartan, otra podría ser la solución mía, para cargar la entidad dentro del mismo contexto:

public Project DeleteProject(int id)
    {
        using (var context = new Context())
        {
            var p = context.Projects.SingleOrDefault(x => x.Id == id);
            if (p == null)
                return p;

            context.Projects.Remove(p);
            context.SaveChanges();
            return p;
        }
    }
esbenr
fuente
2

Sé que esta pregunta es bastante antigua, pero ninguna de las anteriores me funcionó, ya que estaba eliminando registros de más de una clase / servicio y cada uno de ellos estaba creando una instancia de su propio contexto de conexión de base de datos.

Lo que hice para solucionarlo fue enviar el primer contexto creado al resto de clases / servicios que iban a acceder a la base de datos.

Por ejemplo, mi serviceAiba a eliminar algunos de sus registros y llamar serviceBy serviceChacer lo mismo con sus registros.

Entonces yo borrar mis registros en serviceAy pasar como parámetro el contexto creado en la serviceAque serviceBy serviceC.

Terkhos
fuente
2

Puedes escribir este código:

var x=yourquery.FirstOrDefault(); 

sqlEntities.DeleteObject(x);
sqlEntities.SaveChanges();
mehdi
fuente
1

En caso de que nada de lo anterior funcione, puede probar esta solución:

context.Entry(yourObject).State = System.Data.Entity.EntityState.Deleted; context.SaveChanges();

Ala 'Alnajjar
fuente
0

Debe asegurarse de que su objeto existe en la lista de la que está tratando de eliminar, debe poner la siguiente condición

si (context.entity.contains (su objeto))

eliminarlo.

si tiene una condición complicada para la igualdad , debe anular el método de igualdad en la clase de entidad para poner su condición de igualdad, para obtener la forma correcta para un método de extensión "entidad.contacto"

Mohammad Ahmad Abdullah
fuente
0

Asegúrese de que el modelo que pasa a Eliminar (entidad) sea exactamente el mismo que el registro de la base de datos.

Algunas veces es posible pasar el modelo sin algunos campos como Id o Fecha. guárdelos en @ html.Hiddenfor si publica como formulario.

La mejor manera es pasar la ID y obtener la entidad usando el método Find (Id) y pasarla a Remove (Entity)

Espero que esto ayude a alguien.

Dheeraj Palagiri
fuente
0

Tengo este problema y lo soluciono. Simplemente copie el siguiente código:

sqlEntities.Attach(entity);
sqlEntities.Remove(entity);
sqlEntities.SaveChanges();
vahid sabet
fuente
0

En mi caso, hubo un contexto, pero obtuve una entidad con la opción 'AsNoTracking'

vborutenko
fuente