Usuário com melhor resposta
Attach de uma collection em um objeto usando entity framework.

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
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
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
-
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 -
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 -
-
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 -
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 -
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 -
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 -
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.