Usuário com melhor resposta
Checkbox com relacionamento muito para muitos

Pergunta
-
Olá pessoal, estou fazendo um sistema de login, vou expor as classe para contextualizar melhor:
plugin.cs
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace Site.Areas.w7painel.Models { public class Plugin { public int Id { get; set; } public string Nome { get; set; } public string Versao { get; set; } public string Descricao { get; set; } public ICollection<Permissao> Permissoes { get; set; } } }
Permissao.cs
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace Site.Areas.w7painel.Models { public class Permissao { public int Id { get; set; } public string Nome { get; set; } public string Chave { get; set; } public Plugin Plugin { get; set; } public virtual ICollection<Grupo> Grupos { get; set; } } }
Grupo.cs
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace Site.Areas.w7painel.Models { public class Grupo { public int Id { get; set; } public string Nome { get; set; } public ICollection<Permissao> Permissoes { get; set; } } }
Esta são as classes envolvidas, o meu controller esta assim:
GrupoController.cs
[Seguranca] public ActionResult Edit(int id) { var grupo = db.Grupos.Include(x => x.Permissoes).FirstOrDefault(x => x.Id == id); ViewBag.Plugins = db.Plugins.Include(x => x.Permissoes).ToList(); return View(grupo); }
E na view
@using Site.Areas.w7painel.Models @{ ViewBag.Title = "Edit"; Layout = "~/Areas/w7painel/Views/Shared/_Layout.cshtml"; } <h2> Edit</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Grupo</legend> @Html.HiddenFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) @Html.ValidationMessageFor(model => model.Nome) </div> @foreach (var item in (IList<Plugin>)ViewBag.Plugins) { <p>@item.Nome</p> <ul> @foreach (var permissao in item.Permissoes) { <li> <input name="" id="" type="checkbox" value="@permissao.Id"/>@permissao.Nome </li> } </ul> } <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div>
A duvida é como eu construo a minha view para que ela FUNCIONE, como eu preencho o name, e o id, do checkbox, para que ele mostre os valores que já existem selecionados no banco de dados?
Cleyton Ferrari [ twitter: @cleytonferrari - Site: TI Selvagem ]
Respostas
-
Olá pessoal consegui resolver!
Vou postar aqui como eu resolvi para ajudar o pessoal que enfrenta o mesmo problema.
1º tive que criar uma classe para preencher os combobox(viewmodel), uma vez que tenho que mostrar se ele ta ou não selecionado
namespace Site.Areas.w7painel.Models.ViewModel { public class PermissoesAssociadasAoGrupo { public Permissao Permissao { get; set; } public bool Associado { get; set; } } }
Ai no GrupoController.cs
private void PopularPermissoesAssociadas(Grupo grupo) { var todasPermissoes = db.Permissoes.ToList(); var permissoesGrupo = new HashSet<int>(grupo.Permissoes.Select(c => c.Id)); var viewModel = new List<PermissoesAssociadasAoGrupo>(); foreach (var permissao in todasPermissoes) { viewModel.Add(new PermissoesAssociadasAoGrupo { Permissao = permissao, Associado = permissoesGrupo.Contains(permissao.Id) }); } ViewBag.Permissoes = viewModel; ViewBag.Plugins = db.Plugins.ToList(); } private void AtualizarPermissoesNoGrupo(string[] permissoesSelecionadas, Grupo grupoParaAtualizar) { if (permissoesSelecionadas == null) { grupoParaAtualizar.Permissoes = new List<Permissao>(); return; } var permissoesSelecionadasHS = new HashSet<string>(permissoesSelecionadas); var permissoesDoGrupo = new HashSet<int>(grupoParaAtualizar.Permissoes.Select(c => c.Id)); foreach (var permissao in db.Permissoes) { if (permissoesSelecionadasHS.Contains(permissao.Id.ToString())) { if (!permissoesDoGrupo.Contains(permissao.Id)) grupoParaAtualizar.Permissoes.Add(permissao); } else { if (permissoesDoGrupo.Contains(permissao.Id)) grupoParaAtualizar.Permissoes.Remove(permissao); } } } [Seguranca] public ActionResult Edit(int id) { var grupo = db.Grupos.Include(x => x.Permissoes).FirstOrDefault(x => x.Id == id); PopularPermissoesAssociadas(grupo); return View(grupo); } [HttpPost] [Seguranca] public ActionResult Edit([Bind(Exclude = "Permissoes")]Grupo grupo, string[] permissoesSelecionadas) { var grupoParaAtualizar = db.Grupos.Include(x => x.Permissoes).Single(x => x.Id == grupo.Id); if (ModelState.IsValid) { AtualizarPermissoesNoGrupo(permissoesSelecionadas, grupoParaAtualizar); grupoParaAtualizar.Nome = grupo.Nome; db.Entry(grupoParaAtualizar).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } PopularPermissoesAssociadas(grupo); return View(grupo); }
Tive que criar dois metodos para facilitar o preenchimento dos combobox, e mudar a assinatura do Edit, repare que usei,
public ActionResult Edit([Bind(Exclude = "Permissoes")]Grupo grupo, string[] permissoesSelecionadas)
Bind Exclude, para o model não verificar as permissões, uma vez que ela são passadas atraves do parametro permissoesSelecionadas.
E na view,
@using Site.Areas.w7painel.Models @using Site.Areas.w7painel.Models.ViewModel @model Site.Areas.w7painel.Models.Grupo @{ ViewBag.Title = "Edit"; Layout = "~/Areas/w7painel/Views/Shared/_Layout.cshtml"; } <h2> Edit</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Grupo</legend> @Html.HiddenFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) @Html.ValidationMessageFor(model => model.Nome) </div> @foreach (var plugin in (List<Plugin>)ViewBag.Plugins) { <p>@plugin.Nome</p> var dados = (List<PermissoesAssociadasAoGrupo>)ViewBag.Permissoes; var permissoes = dados.Where(x => x.Permissao.Plugin.Id == plugin.Id).ToList(); <ul> @foreach (var permissaoAssociada in permissoes) { <li> <input type="checkbox" name="permissoesSelecionadas" value="@permissaoAssociada.Permissao.Id" @(Html.Raw(permissaoAssociada.Associado ? "checked=\"checked\"" : "")) /> @permissaoAssociada.Permissao.Id @permissaoAssociada.Permissao.Nome </li> } </ul> } <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div>
Bom tai a forma como eu resolvi, não sei se é a melhor forma, mas até agora esta funcionando perfeitamente para mim, se alguem tiver alguma sugestão em cima desse codigo posta ai!
Esse link (http://mikeyhogarth.wordpress.com/2011/02/05/implementing-many-to-many-relationships-in-mvc3/) me ajudou bastante, deem uma olhada!
Cleyton Ferrari [ twitter: @cleytonferrari - Site: TI Selvagem ]
- Marcado como Resposta Cleyton Ferrari sexta-feira, 17 de fevereiro de 2012 13:27