none
Attach de uma collection em um objeto usando entity framework. RRS feed

  • Pergunta

  • Olá pessoal,

    Estou usando entity framework e code first, mvc3.

    Tenho o seguinte cenário: Tenho um usuário que possui uma coleção de áreas (áreas do sistema). Então existe uma entidade usuario, outra áreas e outra UsuarioAreas pois existem atributos de áreas específicas para cada usuário, como por exemplo posição.

    Ao incluir um novo usuário o sistema precisa incluir tb todas as áreas existentes para este usuário.

    Então após a vinda das informações do usuário através do formulário eu populo o usuário e então preciso recuperar todas as áreas existentes e incluir no usuário.

    [HttpPost]
    public ActionResult Create(Usuario usuario)
    {
        try
        {
            usuario.Nome = usuario.Nome;
    ...
            List<Area> AreasDoUsuario = Repository.GetTodasAsAreas();
                    
            usuario.Areas= AreasDoUsuario;
                    
            db.Usuario.Add(usuario);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch 
        {
            return View(usuario);
        }
    }


    public static List<Area> GetTodasAsAreas() { List<Area> AreasExistentes = new List<Area>(); List<UsuarioArea> AreasDoUsuario = new List<UsuarioArea>(); using (var ctx = new Context()) { AreasExistentes areas = ctx.Areas.ToList(); } foreach (var item in AreasExistentes) { UsuarioArea ua = new UsuarioArea(); ua.AreaId = item.Id; ua.Area = item; ua.PosTop = 10;
    ua.PosLeft = 10;
    ua.Ativo = true;
    AreasDoUsuario.Add(ua);

    } return AreasDoUsuario; }


    Eu chamo um repository para recuperar todas as áreas. Ao fazer o SaveChanges, o entity framework não entende que eu quero incluir o usuário mas não quero incluir novas áreas. O que ocorre hoje é que ele está incluindo corretamente o usuário e UsuariosAreas, mas erradamente está incluindo também novas áreas. As áreas são fixas não podem ser duplicadas no banco. Como faço para informar ao entity que não quero incluir novas áreas?

    Obrigado a todos.


    Troque suas Figurinhas repetidas, faça amigos e complete seus álbuns de maneira fácil e divertida.

    Http://www.TrocaFigurinhas.com

    quinta-feira, 11 de outubro de 2012 16:22

Respostas

Todas as Respostas

  • Oá Mvurban,

    Tudo beleza?

    Acredito que este link vai te ajudar: http://ferhenriquef.com/2012/07/07/ef-code-first-design-patterns-asp-net-multi-camadas-e-muito-trabalho/

    É justamente um exemplo que construí para documentar alguns meios de atualização de dados com o Entity Framework.

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    Microsoft MVP - Data Platform Development
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.com/
    Twitter: @ferhenrique
    Entity Framework - Brasil: https://www.facebook.com/EntityFrameworkBrasil

    • Marcado como Resposta Mvurban segunda-feira, 15 de outubro de 2012 15:58
    sábado, 13 de outubro de 2012 13:54
    Moderador
  • Olá Fernando,

    Primeiramente obrigado por responder.
    Antes de ver o seu post, fiquei tentando soluções e a única que funcionou pra mim foi passar para a outra camada o contexto, o que eu não achei nada elegante, mas que resolveu o meu problema.

    Vendo agora o seu blog, percebi que você muda o status de todos os objetos da coleção, um a um através de um foreach. Fiz alguns testes aqui e essa mudança de status deve sempre ser feita no contexto final (principal), ou seja, no contexto onde se fará o save. Tentei setar o status no repository uma vez que já faço um foreach lá, pensando em economizar passos, mas não deu certo, o contexto principal não entendeu. Já havia tentado também mudar o status de toda a coleção, sem um foreach, mas isso não é possível, ou eu não consegui.

    Uma dúvida, se eu tiver vários objetos, milhares, essa mudança de status um a um, não ficaria custoso, ou é um processo rápido, já que está em memória? 

    Só para constar, a mudança de status através do foreach funcionou bem e resolveu o problema de uma forma mais elegante do que enviar o contexto.

    Obrigado.


    Troque suas Figurinhas repetidas, faça amigos e complete seus álbuns de maneira fácil e divertida.

    Http://www.TrocaFigurinhas.com

    segunda-feira, 15 de outubro de 2012 13:59
  • Olá Mvurban,

    Quando mudamos o status de uma entidade nenhum modificação muito custosa é feita, então vc não terá um impacto muito grande de performance. Se tiver uma coleção de tamanho bastante exagerado pode até mesmo utilizar paralelismo para modificar o status das instâncias.

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    Microsoft MVP - Data Platform Development
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.com/
    Twitter: @ferhenrique
    Entity Framework - Brasil: https://www.facebook.com/EntityFrameworkBrasil

    segunda-feira, 15 de outubro de 2012 15:38
    Moderador
  • Só um comentário: porque diabos você tem uma classe usuário? Por que não usar o membership? Só um comentário.

    Sou só uma little padawan que tem sorte de andar com jedis, mas farei o possível por quem precisar :)

    Se precisar: @MayogaX

    segunda-feira, 15 de outubro de 2012 17:48
  • Oi Priscila, 

    Eu uso membership, só que é um custom Membership. De qualquer forma o membership nada tem haver com o meu problema.

    Abraços.


    Troque suas Figurinhas repetidas, faça amigos e complete seus álbuns de maneira fácil e divertida.

    Http://www.TrocaFigurinhas.com

    segunda-feira, 15 de outubro de 2012 19:39
  • Claro que não tem nada a ver. Só achei que você não estava usando e ia aconselhar a usar :)

    O que o mestre Fernando Henrique disse já é o suficiente para ti, eu acho :)


    Sou só uma little padawan que tem sorte de andar com jedis, mas farei o possível por quem precisar :)

    Se precisar: @MayogaX

    segunda-feira, 15 de outubro de 2012 20:15
  • Fernando,

    Agora tive a necessidade de fazer o update. Vi lá no seu blog, como você fez... no meu caso não preciso comparar o que tenho com o que vou alterar, eu sempre apago tudo e recrio com a alteração... mais simples. Percebi que para o Entity entender o relacionamento é necessário fazer uma nova busca no banco incluindo as entidades relacionadas 

    var bookToUpdate = context.Books.Include("Category").Include("Authors").Where(b => b.Id == book.Id).Single();

    e proceder as alterações em cima desse novo objeto "bookToUpdate". É esse mesmo o melhor caminho? Eu não consigo usar o objeto que veio de origem né? no caso o próprio "Model.Book book" e associar as entidades relacionadas nele? O entity não entende isso né?

    Fiz alguns testes aqui e a única maneira que consegui fazer funcionar foi da forma como vc sugere no blog.

    Fico imaginando se o bookToUpdate tiver dezenas de campos, fazer o map de book para bookToUodate vai ser bem chato. Tudo bem...  aqui pode até entrar um Automapper da vida, mais aí uma coisa que deveria ser trivial começa a ficar trabalhosa e complexa demais. Será que a microsoft quer que seja desse jeito mesmo? ou a coisa tente a evoluir pra algo mais intuitivo e direto?

    O que vc acha? 


    Troque suas Figurinhas repetidas, faça amigos e complete seus álbuns de maneira fácil e divertida.

    Http://www.TrocaFigurinhas.com

    segunda-feira, 15 de outubro de 2012 20:27
  • Olá MVUrban,

    Até agora passei pelo mesmo cenário que vc.

    Infelizmente, com um simples Attach não consegui resolver essa questão do relacionamento N para N.

    O Attach funciona muito bem para um escopo mais simples, no qual não precisamos atualizar as demais entidades associadas.

    A forma que geralmente utilizo é esta, infelizmente queria algo mais simples também...

    Não sei se a MS quer que seja deste jeito, até agora não achei outro modo de fazer... Mas não deixo de pesquisar.

    Vamos ver nas próximas versões :)

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    Microsoft MVP - Data Platform Development
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.com/
    Twitter: @ferhenrique
    Entity Framework - Brasil: https://www.facebook.com/EntityFrameworkBrasil

    segunda-feira, 15 de outubro de 2012 22:13
    Moderador
  • Como você está usando MVC, a maneira mais correta não é atualizar o objeto que vem por parametro, e sim pegar o Id que veio por POST, buscar esse objeto pelo Entity Framework  pq nesse caso o Entity framework vai conseguir fazer o track das mudanças que você fizer no objeto,(adicionar novos objetos a coleções por exemplo), e depois usar o método.

    TryUpdateModel() passando o objeto que você buscou pelo Entity Framework.

    quinta-feira, 18 de outubro de 2012 01:17