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

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

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 .


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

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.


2

Você pode escrever este código:

var x=yourquery.FirstOrDefault(); 

sqlEntities.DeleteObject(x);
sqlEntities.SaveChanges();

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();


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"


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.


0

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

sqlEntities.Attach(entity);
sqlEntities.Remove(entity);
sqlEntities.SaveChanges();

0

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.