none
Erro: Entity object cannot be referenced by multiple instances of IEntityChangeTracker RRS feed

  • Pergunta

  • Bom dia pessoal, 

    Já estou a um tempinho quebrando a cabeça para fazer uma arquitetura para acesso a dados em um projeto. As premissas são:

    1. Estou usando o Entity Framework 6. 
    2. Lazy Load está ativado
    3. Quero trabalhar da mesma forma que Nhibernate (carregar o objeto por completo. Alterar o que eu quero e persisti-lo no banco)

    O meu cenário é o seguinte: 

    • Tenho um objeto Usuário que possui 1 ou várias Permissões.
    • Esse problema está acontecendo quando quero atualizar os dados do usuário. 
    • Descrição da alteração: Pego o Id do usuário selecionando. Dou um Find pelo entity framework, altero os dados e depois dou um Update.

    Segue os códigos:

    Essa é minha classe de Repositório

    public abstract class Repository<TEntity> : IDisposable, IRepository<TEntity> where TEntity : class
        {
            public SysAdmEntities ctx = new SysAdmEntities();
                
            public IList<TEntity> Selecionar()
            {
                IList<TEntity> list;
    
                list = ctx.Set<TEntity>().ToList();
    
                return list;
            }
    
            public IList<TEntity> Selecionar(Func<TEntity, bool> predicate)
            {
                return Selecionar().Where(predicate).ToList();
            }
    
            public TEntity Selecionar(params object[] key)
            {
                TEntity entity = ctx.Set<TEntity>().Find(key);
    
                return entity;
            }
    
            public void Atualizar(TEntity obj)
            {
                ctx.Entry(obj).State = EntityState.Modified;
            }
    
            public void SalvarTodos()
            {
                ctx.SaveChanges();
            }
    
            public TEntity Adicionar(TEntity obj)
            {
                return ctx.Set<TEntity>().Add(obj);
            }
    
            public void Excluir(Func<TEntity, bool> predicate)
            {
                ctx.Set<TEntity>()
                    .Where(predicate).ToList()
                    .ForEach(del => ctx.Set<TEntity>().Remove(del));
            }
    
            public void Excluir(TEntity obj)
            {
                ctx.Set<TEntity>().Remove(obj);
            }
    
            public void Dispose()
            {
                ctx.Dispose();
            }
        }

    Esse é minha Classe de Negócio do Usuário

    public partial class UsuarioBusiness
        {
    
            /// <summary>
            /// Método repsonsável por realizar uma buscar por login do usuário
            /// </summary>
            /// <param name="login"></param>
            /// <returns></returns>
            public usuario_tb Buscar(string login)
            {
                usuario_tb usuario;
    
                using (var repostiorio = new UsuarioDAL())
                {
                    usuario = repostiorio.Selecionar(p => p.login == login && p.situacao == "A").SingleOrDefault();
                }
    
                return usuario;
            }
    
            /// <summary>
            /// Método responsável por validar o login do usuário
            /// </summary>
            /// <param name="login"></param>
            /// <param name="senha"></param>
            /// <returns></returns>
            public string VerificarLogin(string login, string senha)
            {
                string resultado = "";
                usuario_tb usuario = Buscar(login);
    
                //Verifico se o usuário existe
                if (usuario != null)
                {
                    if (usuario.senha != senha)
                    {
                        resultado = "Senha inválida!";
                    }
                }
                else
                {
                    resultado = "Usuário inválido!";
                }
    
    
                return resultado;
            }
    
            
            /// <summary>
            /// Método responsável por retornar todos os usuário registrados
            /// </summary>
            /// <returns></returns>
            public IList<usuario_tb> Listar()
            {
                IList<usuario_tb> usuarioLista;
    
                using (var repostiorio = new UsuarioDAL())
                {
                    usuarioLista = repostiorio.Listar();
                }
    
                return usuarioLista;
            }
    
            /// <summary>
            /// Retorna o usuário pelo Id
            /// </summary>
            /// <param name="usuarioId"></param>
            /// <returns></returns>
            public usuario_tb Buscar(int usuarioId)
            {
                usuario_tb usuario;
    
                using (var repostiorio = new UsuarioDAL())
                { 
                   usuario = repostiorio.Buscar(usuarioId);
                }
    
                return usuario;
            }
    
            /// <summary>
            /// Método reponsável por deletar um usuário registrado
            /// </summary>
            /// <param name="usuario"></param>
            /// <returns></returns>
            public void Deletar(usuario_tb usuario)
            {
                using (var repostiorio = new UsuarioDAL())
                {
                    repostiorio.Excluir(usuario);
                    repostiorio.SalvarTodos();
                }
            }
    
            /// <summary>
            /// Método responsável por atualizar um usuário específico
            /// </summary>
            /// <param name="usuario"></param>
            /// <returns></returns>
            public void Ataulizar(usuario_tb usuario)
            {
                using (var repostiorio = new UsuarioDAL())
                {
                    repostiorio.Atualizar(usuario);
                    repostiorio.SalvarTodos();
                }
            }
    
            /// <summary>
            /// Método responsável por inserir um novo usuário
            /// </summary>
            /// <param name="usuario"></param>
            /// <returns></returns>
            public usuario_tb Inserir(usuario_tb usuario)
            {
    
                using (var repostiorio = new UsuarioDAL())
                {
                    usuario = repostiorio.Adicionar(usuario);
                    repostiorio.SalvarTodos();
                }
    
                return usuario;
            }
        }

    Esse é o trecho que está dando o erro

    //Atualizo o objeto selecionado
    GridDataItem dataItem = rgUsuario.SelectedItems[0] as GridDataItem;
    int usuarioId = Convert.ToInt32(dataItem.GetDataKeyValue("usuario_id"));
    
    //Trago objeto do banco de dados
    usuario_tb usuario = base.Business.Buscar(usuarioId);
    
    usuario.login = rtbLogin.Text;
    usuario.senha = ysAdm.Util.Util.criptografar(rtbSenha.Text, chaveCriptografia);
    usuario.situacao = rcbSituacao.SelectedValue;
    usuario.dt_alteracao = DateTime.Now;
    usuario.permissao_tb.Clear();
    
    //Cria um nova permissão para o novo usuário
    permissao_tb permissao = new permissao_tb() 
    {
      perfil_id = Convert.ToInt32(rcbPerfil.SelectedValue)
      ,dt_inclusao = DateTime.Now
      ,usuario_tb = usuario
      ,usuario = base.usuarioLogado.usuario_id
    };
    
    //Adicionando a nova permissão na lista de permissão do usuário
    usuario.permissao_tb.Add(permissao);
    
    base.Business.Ataulizar(usuario);
    Desde já agradeço a ajuda.

    sexta-feira, 22 de julho de 2016 13:54

Todas as Respostas

  • Cara, 

    Você tem um erro de abertura de instancia , tem q analisar o estado da sua conexão , por que ela ta aberta, e você ta tentando abrir ela novamente para persistir os dados. fecha a instancia que você esta abrindo .... depois quando for atualizar abre uma nova !!!! sugiro q coloque o Break Point e veja o passo a passo ..... 


    Diego Almeida Barreto&lt;/strong&gt; &lt;br/&gt; &lt;em&gt;System Analyst / Software Developer&lt;/em&gt; &lt;br/&gt; &lt;img &lt;/p&gt; &lt;/div&gt;

    sexta-feira, 22 de julho de 2016 15:53
  • Fala Diego,

    Quando você diz que minha conexão está aberta você refere-se a este objeto?

    public SysAdmEntities ctx = new SysAdmEntities();

    Toda classe de negócio faz a consulta ao seu repositório usando o:

    using (var repostiorio = new UsuarioDAL())
    {
     ....
    }

    No final desse bloco ele chama o método Dispose da Classe Repository

    public void Dispose()
    {
        ctx.Dispose();
    }

    Quando esse método é chamado ele não encerra o uso da conexão?

    Obrigado.

    sexta-feira, 22 de julho de 2016 16:27
  • Isso, 

    Isso a sua classe que Herda a DbContext, deve ser aSysAdmEntities.

    Alguma coisa ta se perdendo , vc esta utilizando o RepositoryPatterns , vi que em um metodo dispose(), aonde vc ta chamando esse cara, pq na teoria ele q iria dar o dispose na seu context, tem q ver em q classe a sua UsuarioDAL n ta implementando o IDisposable, pq se tiver vc deve ta dando dispose em nada.



    Diego Almeida Barreto&lt;/strong&gt; &lt;br/&gt; &lt;em&gt;System Analyst / Software Developer&lt;/em&gt; &lt;br/&gt; &lt;img &lt;/p&gt; &lt;/div&gt;

    sexta-feira, 22 de julho de 2016 19:50
  • Então...

    Quem implementa o IDisposable é o próprio repositório

    public abstract class Repository<TEntity> : IDisposable, 


    E a UsuarioDAL herda Repository 

    public partial class UsuarioDAL : Repository<usuario_tb>

    Teoricamente nao está se perdendo. O coloquei o break point no metodo e ele está sendo acionado.

    sexta-feira, 22 de julho de 2016 20:47