O objeto não pode ser excluído porque não foi encontrado no ObjectStateManager

114

Estou recebendo este erro "O objeto não pode ser excluído porque não foi encontrado no ObjectStateManager."

Meu código é:

    protected MyEntities sqlEntities;

    public virtual void Delete(TEntity entity)
    {
        System.Type t = typeof(TEntity);
        sqlEntities.DeleteObject(entity);
        sqlEntities.SaveChanges();
    }
Sami
fonte
5
Desculpe, houve um problema no código em que diferentes objetos datacontext foram usados ​​para buscar e excluir o registro.
Sami,
Eu tive um bug como este: var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);Eu estava tentando criar uma entidade simulada com seu PK definido corretamente, na esperança de que o Entity Framework chamasse DeleteObject com base no PK
C. Tewalt

Respostas:

156

Isso significa que a entidade não está anexada (não foi carregada pela mesma instância de contexto). Experimente isto:

protected MyEntities sqlEntities;

public virtual void Delete(TEntity entity)
{
    sqlEntities.Attach(entity);
    sqlEntities.DeleteObject(entity);
    sqlEntities.SaveChanges();
}
Ladislav Mrnka
fonte
1
Obrigado Ladislav. Isso me ajudou quando eu tinha dois contextos acontecendo ao excluir dados filho de um pai - que foi chamado de um contexto diferente, fora de um TransactionScope. Mudei a chamada pai dentro do escopo e mesmo contexto e meu problema foi resolvido.
dan richardson
1
@Ladislav: Se eu usar .Attach, recebo um erro diferente: "Um objeto de entidade não pode ser referenciado por várias instâncias de IEntityChangeTracker." Isso significa que já existem outras instâncias de objeto ativas impedindo a exclusão?
Matt,
2
@Matt: Não, significa que seu objeto já está anexado a outro contexto. Não pode ser anexado a dois ao mesmo tempo. Você deve usar o contexto original para excluir a entidade.
Ladislav Mrnka
@Ladislav: Obrigado, isso me ajudou a procurar mais - encontrei esta pergunta que parece responder como abordá-la: É possível verificar se um objeto já está anexado a um contexto de dados no Entity Framework? . Você está certo, esse parece ser o problema no meu caso. Obrigado pela resposta rápida!
Matt,
Obrigado pelo lembrete, eu o anexei apenas quando estava atualizando um registro, mas não quando estava excluindo um registro.
pinmonkeyiii
60

Apenas um pequeno esclarecimento sobre a resposta de Ladislav Mrnka (que deve ser a resposta aceita).

Se gosta de mim, você tem o código em um formato como este:

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

.. então é isso que você quer fazer:

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

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

Talvez isso pareça óbvio, mas não estava claro para mim inicialmente que era necessário especificar a entidade a que se atentar, e não apenas o contexto .

Kjartan
fonte
1
Eu uso essa abordagem e recebo a exceção: "A instrução de atualização, inserção ou exclusão de armazenamento afetou um número inesperado de linhas (0). As entidades podem ter sido modificadas ou excluídas desde que as entidades foram carregadas. Atualize as entradas ObjectStateManager."
kat1330
11

Apenas para propergar a explicação de Kjartans:

Eu tinha:

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

O problema é que usei meu próprio método (GetProject ()) para obter a entidade (portanto, usando outro contexto para carregar a entidade):

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;      
        }
    }

Uma solução poderia ser anexar a entidade carregada conforme Kjartan declara, outra poderia ser a solução da mina, para carregar a entidade dentro do mesmo 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
fonte
2

Eu sei que esta questão é bastante antiga, mas nenhuma das opções acima funcionou para mim, já que eu estava excluindo registros de mais de uma classe / serviço e cada um deles estava instanciando seu próprio contexto de conexão de banco de dados.

O que fiz para resolver foi enviar o primeiro contexto criado para o resto das classes / serviços que iam aceder à base de dados.

Por exemplo, eu serviceAiria deletar alguns de seus registros e chamar serviceBe serviceCfazer o mesmo com seus registros.

Eu então excluiria meus registros em serviceAe passaria como parâmetro o contexto criado em serviceApara serviceBe serviceC.

Terkhos
fonte
2

Você pode escrever este código:

var x=yourquery.FirstOrDefault(); 

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

Caso nenhuma das opções acima funcione, você pode tentar esta solução:

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

Ala 'Alnajjar
fonte
0

Você deve ter certeza de que seu objeto existe na lista da qual você está tentando remover, você deve colocar a seguinte condição

if (context.entity.contains (seu objeto))

remova.

se você tiver uma condição complicada de igualdade, você deve substituir o método igual na classe de entidade para colocar sua condição de igualdade, para obter o caminho certo para um método de extensão "entity.contains"

Mohammad Ahmad Abdullah
fonte
0

Certifique-se de que o modelo que passa para Remover (Entidade) é exatamente o mesmo que o registro do banco de dados.

Algumas vezes é possível passar o modelo sem alguns campos como Id ou Data. mantenha-os em @ html.Hiddenfor se você postar como formulário.

A melhor maneira é passar o ID e obter a entidade usando o método Find (Id) e passá-lo para Remove (Entity)

Espero que isso ajude alguém.

Dheeraj Palagiri
fonte
0

Eu tenho esse problema e resolvo. Basta copiar o código abaixo:

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

No meu caso, havia um contexto, mas recebi a entidade com a opção 'AsNoTracking'

Vborutenko
fonte