Inquiridor
Erro: Entity object cannot be referenced by multiple instances of IEntityChangeTracker

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:
- Estou usando o Entity Framework 6.
- Lazy Load está ativado
- 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.
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</strong> <br/> <em>System Analyst / Software Developer</em> <br/> <img </p> </div>
-
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.
-
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</strong> <br/> <em>System Analyst / Software Developer</em> <br/> <img </p> </div>
-
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.