none
Como trabalhar com Herança de Pessoa, Pessoa Física e Pessoa Jurídica no MVC 4 RRS feed

  • Pergunta

  • Pessoal estou modelando um projeto de um cadastro de Clientes e Contas a Pagar, para isso estou tentando aprender a usar o MVC 4, com Razor e Code First.

    No meu sistema os Clientes podem podem ser pessoas físicas ou jurídicas, e aí que começa o meu problema.

    Para vincular o cliente (PF ou PJ) com a classe Contas a Pagar estou linkando diretamente as classes Contas a Pagar e Cliente.

    O problema está sendo na hora de trabalhar com esse Cliente, porque o relacionamento da tabela Contas a Pagar é feito com a classe Cliente e não com a suas classes especializadas.

    Quando preciso enviar para a View uma listagem de clientes eu uso o seguinte método para recuperar os clientes:

    var pf = db.Pessoa.OfType<PessoaFisica>();
    var pj = db.Pessoa.OfType<PessoaJuridica>();

    A partir daí monto uma viewCliente em envio para tela, sem problemas.

    Só que como eu faço para trabalhar a parte de edição, criação e delete usando MVC 4 e Razor?

    Continuo trabalhando com views?

    Crio um controller especializado para isso?

    Não tenho nenhuma experiência com essa tecnologia e estou apanhando um bocado tentando encontrar uma solução.

    Estou acostumando a trabalhar com Webforms mas gostaria de evoluir para uma tecnologia mais nova.

    Então se alguém puder me dar uma dica fico muito grato.



    Ricardo Cardoso


    terça-feira, 23 de abril de 2013 05:32

Todas as Respostas

  • Olá, pode utilizar o mesmo controller pra tudo, só deve criar mecanismos para gerenciar o conteúdo por exemplo você pode passa o objeto PessoaJuridica para view e a view checar o tipo.

    @if(Model is PessoaJuridica)
    {
    @Html.PartialView("CreatePJ")
    }else{
    @Html.PartialView("CreatePF")
    }

    Como PessoaFisica e PessoaJuridica herdam de Pessoa você pode retornar para o action Pessoa

    [HttpPost]
    public ActionResult Create(Pessoa pessoa)
    {
       db.Pessoa.Add(pessoa);
       return RedictToAction("Index");
    }


    Não esqueça de marcar o post como útil caso tenha te ajudado.

    terça-feira, 23 de abril de 2013 14:25
  • E nesse caso não haveria problemas na tipagem do objeto, quero dizer, se o meu controller está esperando enviar uma Pessoa e eu enviar uma Pessoa Fisica não vai dar problema no model?

    Eu não conheço muito esse conceito de PartialView pelo que vc falou posso usar ele para renderizar PF ou PF na minha view é isso?



    Ricardo Cardoso

    terça-feira, 23 de abril de 2013 16:57
  • Olá Ricardo.

    Bem, o MVC é um padrão de desenvolvimento interessante, muito interessante. Eu particularmente, prefiro.

    Marco deu a resposta.

    Abraço


    Desenvolva!!!

    terça-feira, 23 de abril de 2013 19:42
  • Isso, você criaria uma PartialView fortemente tipada para cada um, segue abaixo um post legal sobre Partial Views.

    ASP .NET MVC 3 - Apresentando Partial Views



    Não esqueça de marcar o post como útil caso tenha te ajudado.

    terça-feira, 23 de abril de 2013 20:07
  • Valeu marco vou dar uma testada hoje ainda.

    Pra mim está mais difícil essa mudança de pensamento do webforms para o padrão mvc do asp.net.

    Isso está atrapalhando todo o desenvolvimento de uma coisa que seria simples, seria apenas criar um CRUD para trabalhar com um cadastro de clientes que podem ser pf ou pj, mas vamos em frente que aprender que é sempre bom aprender coisas novas.


    Ricardo Cardoso

    terça-feira, 23 de abril de 2013 21:09
  • Você terá um cadastro para cada tipo de cliente? ou seja, um cadastro para PJ e outro para PF?

    Acho que você deveria ver o conceito de ViewModel, ao invés de tipar sua View com o objeto de domínio.

    No seu caso você criaria uma classe ClienteViewModel por exemplo, e esta seria a classe a tipar sua View, no get da sua página de cadastro, você simplesmente mapeia seu objeto de domínio (PJ ou PF) para a view model.

    Abs

    terça-feira, 23 de abril de 2013 21:17
  • Pois é Rafael é exatamente isso que estava tentando fazer.

    Criar um cadastro para clientes independente do tipo, porém não estou conseguindo trabalhar com a minha classe ClienteViewModel, não consigo mapear corretamente os tipos que ela pode se desdobrar.


    Ricardo Cardoso

    terça-feira, 23 de abril de 2013 21:31
  • Sua ViewModel deve possuir os campos tanto de PJ como PF, acredito que em sua tabela deva haver uma campo tipoCliente ou algo do tipo que diferencie um do outro, certo?

    Via javascript ou jquery você define o que deve ser exibido para cada tipo de cliente.

    Se não clareou, coloca uma parte de seu código aí!

    Abs

    terça-feira, 23 de abril de 2013 21:35
  • Tratar apenas uma ViewModel como todos as propriedades(PF e PJ) funciona, mas com isso você irá ter retrabalho tanto na hora de preencher o objeto viewModel quanto na hora de receber os dados no controller.


    Não esqueça de marcar o post como útil caso tenha te ajudado.

    terça-feira, 23 de abril de 2013 22:48
  • Então vou colocar o que estou tentando montar pra ver se dá uma clareada:

    Criei um modelo viewCliente que uso para transportar os dados do controller para a home, ele pode ser tanto pessoa fisica quanto jurídica. Para organizar o que é pf ou pj criei uma classe auxiliar que é TipoCliente e uso ela para popular a DropDown que ajudará a controlar o tipo de pessoa que está sendo criado.

        public class TipoCliente
        {
            public int TipoClienteId { get; set; }
            public string Nome { get; set; }
    
            [Display(Name = "Tipo de Pessoa")]
            public string TipoPessoa { get; set; }
        }
    
        public class viewCliente
        {
            public IEnumerable<TipoCliente> TipoClienteOpcoes = new List<TipoCliente>()
                                                                     {
                                                                         new TipoCliente()
                                                                             {TipoClienteId = 1, Nome = "Pessoa Física"},
                                                                         new TipoCliente()
                                                                             {TipoClienteId = 2, Nome = "Pessoa Jurídica"},
    
                                                                     };
            [Required] 
            [Display(Name = "Tipo")]
            public int tipo { get; set; }
            [Required] 
            [Display(Name = "Tipo")]
            public TipoCliente Tipo
            {
                get
                {
                    return TipoClienteOpcoes.FirstOrDefault(x => x.TipoClienteId == tipo);
                }
            }
    
            [Display(Name = "CPF/CNPJ")]
            public string viewCpfCnpj { get; set; }
    
            #region PF
            public string cpf { get; set; }
            public int rg { get; set; }
            #endregion
    
            #region PJ
            public string cnpj { get; set; }
            public int inscricaoEstadual { get; set; }
            #endregion
    
            public bool Ativo { get; set; }
    
            public int IdCliente { get; set; }
    
            public string Nome { get; set; }
    
            [DisplayFormat(DataFormatString = "{0:dd/mm/yyyy}")]
            public DateTime Data { get; set; }
    
            public string Telefone { get; set; }
    
            public string Email { get; set; }
    
        }

    No primeiro edit do Controller de pessoa eu faço a recuperação do registro escolhido e verifico se é pf ou pj, depois disso monto a viewCliente que será enviada para a View. Já no segundo(que não está sequer entrando) eu faria o tratamento do que está sendo retornado da View e gravaria se for pf ou pj. Porém não estou conseguindo recuperar o model da tela.

            public ActionResult Edit(int id = 0)
            {
                PessoaFisica pf = db.Pessoa.OfType<PessoaFisica>().FirstOrDefault(x => x.idPessoa == id);
                if (pf != null)
                {
                    return View(new viewCliente
                                    {
                                        Ativo = pf.ativa,
                                        IdCliente = pf.idPessoa,
                                        Nome = pf.nome,
                                        tipo = 1,
                                        viewCpfCnpj = pf.cpf,
                                        cpf = pf.cpf,
                                        rg = pf.rg,
                                        Telefone = pf.telefonePrincipal,
                                        Email = pf.emailPrincipal
                                    });
                }
                else
                {
                    PessoaJuridica pj = db.Pessoa.OfType<PessoaJuridica>().FirstOrDefault(x => x.idPessoa == id);
                    if (pj != null)
                    {
                        return View(new viewCliente
                                        {
                                            Ativo = pj.ativa,
                                            IdCliente = pj.idPessoa,
                                            Nome = pj.nome,
                                            tipo = 2,
                                            viewCpfCnpj = pj.cnpj,
                                            cnpj = pj.cnpj,
                                            inscricaoEstadual = pj.inscricaoEstadual,
                                            Telefone = pj.telefonePrincipal,
                                            Email = pj.emailPrincipal
    
                                        });
                    }
                }
                return HttpNotFound();
            }
    
            [HttpPost]
            public ViewResult Edit(viewCliente pessoa)
            {
                if (ModelState.IsValid)
                {
                    db.Entry(pessoa).State = EntityState.Modified;
                    db.SaveChanges();
                    //return RedirectToAction("Index");
                }
                return View();
            }
    Na tela eu faço uma validação para a exibição dos campos e nada mais.

    @using MvcApplicationTesteNet.Models @model viewCliente @{ ViewBag.Title = "Edit"; } <h2> Edit</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Pessoa</legend> @Html.HiddenFor(model => model.IdCliente) <div class="editor-label"> @Html.LabelFor(model => model.Ativo) </div> <div class="editor-field"> @Html.EditorFor(model => model.Ativo) @Html.ValidationMessageFor(model => model.Ativo) </div> <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> <div class="editor-label"> @Html.LabelFor(m => m.Tipo) </div> <div class="editor-field"> @Html.DropDownListFor(m => m.Tipo, new SelectList(Model.TipoClienteOpcoes, "TipoClienteId", "Nome"), "Selecione",

    new{onchange = "MudaTela();",}) </div> <script type="text/javascript"> jQuery(document).ready(function () { MudaTela(); }); function MudaTela() { var e = document.getElementById("Tipo"); var strUser = e.options[e.selectedIndex].value; if (strUser == "1") { jQuery("#divFisica").show(); jQuery("#divJuridica").hide(); } else { jQuery("#divFisica").hide(); jQuery("#divJuridica").show(); } }; </script> <div id="divFisica" style="display: @(Model.Tipo.TipoClienteId == 1) ? block : none"> <div class="editor-label"> @Html.LabelFor(model => model.rg) </div> <div class="editor-field"> @Html.EditorFor(model => model.rg) @Html.ValidationMessageFor(model => model.rg) </div> <div class="editor-label"> @Html.LabelFor(model => model.cpf) </div> <div class="editor-field"> @Html.EditorFor(model => model.cpf) @Html.ValidationMessageFor(model => model.cpf) </div> </div> <div id="divJuridica" style="display: @(Model.Tipo.TipoClienteId == 2) ? block : none"> <div class="editor-label"> @Html.LabelFor(model => model.cnpj) </div> <div class="editor-field"> @Html.EditorFor(model => model.cnpj) @Html.ValidationMessageFor(model => model.cnpj) </div> <div class="editor-label"> @Html.LabelFor(model => model.inscricaoEstadual) </div> <div class="editor-field"> @Html.EditorFor(model => model.inscricaoEstadual) @Html.ValidationMessageFor(model => model.inscricaoEstadual) </div> </div> <div class="editor-label"> @Html.LabelFor(model => model.Data) </div> <div class="editor-field"> @Html.EditorFor(model => model.Data) @Html.ValidationMessageFor(model => model.Data) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <div class="editor-label"> @Html.LabelFor(model => model.Telefone) </div> <div class="editor-field"> @Html.EditorFor(model => model.Telefone) @Html.ValidationMessageFor(model => model.Telefone) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") <script type="text/javascript"> $(document).ready(function () { $("#data").datepicker({ dateFormat: 'dd/mm/yy' }); }); </script> }


    Porém ainda não tive sucesso, agora a noite vou tentar as soluções que vcs propuseram para tentar finalizar essa etapa.

    Mas se tiverem alguma sugestão podem mandar que estou considerando todas as possibilidades.


    Ricardo Cardoso

    terça-feira, 23 de abril de 2013 23:43
  • Ricardo segue o link de um projeto que criei de exemplo tratando herança de uma forma bem simples.

    https://bitbucket.org/marcorsouza/exemplosmvc


    Não esqueça de marcar o post como útil caso tenha te ajudado.

    quinta-feira, 25 de abril de 2013 04:05