none
Checkbox com relacionamento muito para muitos RRS feed

  • 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 ]

    quarta-feira, 15 de fevereiro de 2012 16:03

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
    sexta-feira, 17 de fevereiro de 2012 13:27