none
MVC 5 - Criar uma view que tenha como fonte 2 models RRS feed

  • Pergunta

  • Boa tarde, 

    Tenhos duas models com relacionamento 1:N. Cada model possui suas respectivas views, no entanto, existe a necessidade de uma terceira view que mostre dados das duas models.

    Por exemplo: Model 1 > Nome, Tipo

        Model 2 > Tipo, Código

    Cada model tem seus respectivos controllers e views... View 1 mostra Nome e Tipo.... View 2 mostra Tipo e Código...

    Minha dúvida é: Como faço para criar uma terceira view que mostre Nome, Tipo e Código?


    quarta-feira, 26 de agosto de 2015 16:31

Respostas

  • Voce tem que usar uma view_model

    Na verdade o modelo mais indicado para trabalhar com MVC é no lugar do  "Model" voce trabalhar com "View Model"

    A view Model nao representa o modelo do banco de dados e sim o que voce quer exibir.. por exemplo, essa classe abaixo é model:

    public class Employee : IEntity
    {
         public int Id { get; set; }  // Employee's unique identifier
         public string FirstName { get; set; }  // Employee's first name
         public string LastName { get; set; }  // Employee's last name
         public DateTime DateCreated { get; set; }  // Date when employee was created
    }


    mas eu nao preciso nem do ID nem DateCreated para a construçao da minha view, entao eu crio uma viewmodel:

    public class CreateEmployeeViewModel
    {
         public string FirstName { get; set; }
         public string LastName { get; set; }
    }


    minha view é criada com a viewmodel:

    @model MyProject.Web.ViewModels.CreateEmployeeViewModel
    
    <table>
         <tr>
              <td><b>First Name:</b></td>
              <td>@Html.TextBoxFor(x => x.FirstName, new { maxlength = "50", size = "50" })
                  @Html.ValidationMessageFor(x => x.FirstName)
              </td>
         </tr>
         <tr>
              <td><b>Last Name:</b></td>
              <td>@Html.TextBoxFor(x => x.LastName, new { maxlength = "50", size = "50" })
                  @Html.ValidationMessageFor(x => x.LastName)
              </td>
         </tr>
    </table>


    e é no controler que é feito a transferencia:

    public class EmployeeController : Controller
    {
         private readonly IEmployeeService employeeService;
    
         public EmployeeController(IEmployeeService employeeService)
         {
              this.employeeService = employeeService;
         }
    
         public ActionResult Create()
         {
              CreateEmployeeViewModel viewModel = new CreateEmployeeViewModel();
    
              return View(viewModel);
         }
    
         public ActionResult Create(CreateEmployeeViewModel viewModel)
         {
              // Do what ever needs to be done before adding the employee to the database
         }
    }

    ou seja, crie uma classe com Nome, Tipo e Codigo e depois crie um objeto com os valores corretos vindos do banco.

    Isso tambem cria uma camada mais estavel e independente para view.

    Veja o artigo abaixo:

    http://eduardopires.net.br/2013/08/asp-net-mvc-view-model-pattern-quando-e-como-utilizar/

    att


    William John Adam Trindade
    Analyste-programmeur
    ----------------------------------------------------------

    • Sugerido como Resposta Aline Mansur quinta-feira, 27 de agosto de 2015 12:44
    • Marcado como Resposta welington jrModerator quinta-feira, 14 de dezembro de 2017 17:30
    quarta-feira, 26 de agosto de 2015 19:57
    Moderador
  • quinta-feira, 27 de agosto de 2015 12:37
    Moderador

Todas as Respostas

  • Voce tem que usar uma view_model

    Na verdade o modelo mais indicado para trabalhar com MVC é no lugar do  "Model" voce trabalhar com "View Model"

    A view Model nao representa o modelo do banco de dados e sim o que voce quer exibir.. por exemplo, essa classe abaixo é model:

    public class Employee : IEntity
    {
         public int Id { get; set; }  // Employee's unique identifier
         public string FirstName { get; set; }  // Employee's first name
         public string LastName { get; set; }  // Employee's last name
         public DateTime DateCreated { get; set; }  // Date when employee was created
    }


    mas eu nao preciso nem do ID nem DateCreated para a construçao da minha view, entao eu crio uma viewmodel:

    public class CreateEmployeeViewModel
    {
         public string FirstName { get; set; }
         public string LastName { get; set; }
    }


    minha view é criada com a viewmodel:

    @model MyProject.Web.ViewModels.CreateEmployeeViewModel
    
    <table>
         <tr>
              <td><b>First Name:</b></td>
              <td>@Html.TextBoxFor(x => x.FirstName, new { maxlength = "50", size = "50" })
                  @Html.ValidationMessageFor(x => x.FirstName)
              </td>
         </tr>
         <tr>
              <td><b>Last Name:</b></td>
              <td>@Html.TextBoxFor(x => x.LastName, new { maxlength = "50", size = "50" })
                  @Html.ValidationMessageFor(x => x.LastName)
              </td>
         </tr>
    </table>


    e é no controler que é feito a transferencia:

    public class EmployeeController : Controller
    {
         private readonly IEmployeeService employeeService;
    
         public EmployeeController(IEmployeeService employeeService)
         {
              this.employeeService = employeeService;
         }
    
         public ActionResult Create()
         {
              CreateEmployeeViewModel viewModel = new CreateEmployeeViewModel();
    
              return View(viewModel);
         }
    
         public ActionResult Create(CreateEmployeeViewModel viewModel)
         {
              // Do what ever needs to be done before adding the employee to the database
         }
    }

    ou seja, crie uma classe com Nome, Tipo e Codigo e depois crie um objeto com os valores corretos vindos do banco.

    Isso tambem cria uma camada mais estavel e independente para view.

    Veja o artigo abaixo:

    http://eduardopires.net.br/2013/08/asp-net-mvc-view-model-pattern-quando-e-como-utilizar/

    att


    William John Adam Trindade
    Analyste-programmeur
    ----------------------------------------------------------

    • Sugerido como Resposta Aline Mansur quinta-feira, 27 de agosto de 2015 12:44
    • Marcado como Resposta welington jrModerator quinta-feira, 14 de dezembro de 2017 17:30
    quarta-feira, 26 de agosto de 2015 19:57
    Moderador
  • Certo, compreendi a vantagem de utilizar a View Model. 

    No controller, é possível trazer do banco os valores através de uma query Linq e atribuir estes valores à instância da classe View Model?

    Exemplo: 

    var query = from m in model1
                select m


    quinta-feira, 27 de agosto de 2015 10:17
  • quinta-feira, 27 de agosto de 2015 12:37
    Moderador
  • William, primeiramente muito obrigado pela ajuda.

    Eu estava tentando seguir o exemplo do seu código, mas não consegui compreender a aplicação deste trecho:

    public class EmployeeController : Controller
    {
         private readonly IEmployeeService employeeService;
    
         public EmployeeController(IEmployeeService employeeService)
         {
              this.employeeService = employeeService;
         }

    Você poderia me ajudar novamente?

    Criei a classe view model, mas ainda estou "apanhando" para realizar a transferência no controller.

    Obrigado.

    sexta-feira, 28 de agosto de 2015 16:26
  • o codigo que eu postei é completamente hipotetico, basicamente sao dois objetos que possuem exatamente a mesma interface, o que na maioria das vezes é falso..

    poste seu codigo do controler., desta forma nos poderemos te ajudar mais.

    att


    William John Adam Trindade
    Analyste-programmeur
    ----------------------------------------------------------

    sexta-feira, 28 de agosto de 2015 16:47
    Moderador
  • Vamos lá, vou postar uma exemplo simplificado do que necessito:

    Tenho duas Models com relacionamento 1:N

    namespace TesteViewModel.Models
    {
        [Table("Pessoas")]
        public class Pessoa
        {
            
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public int PessoaID { get; set; }
            public string Nome { get; set; }
    
            [Key]
            public int Cpf { get; set; }
    
            public virtual ICollection<Veiculo> Veiculos { get; set; }
        }
    }
    namespace TesteViewModel.Models
    {
        [Table("Veiculos")]
        public class Veiculo
        {
            [Key]
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public int VeiculoID { get; set; }
    
            public string Modelo { get; set; }
    
            public int CodigoProprietario { get; set; }
    
            [ForeignKey("CodigoProprietario")]
            public virtual Pessoa Pessoa { get; set; }
        }
    

    Devido a necessidade de mostrar em uma view o resultado de uma consulta "join" entre as duas tabelas, criei uma ViewModel.

    namespace TesteViewModel.ViewModels
    {
        public class JoinViewModel
        {
            [Key]
            public int CpfProprietario { get; set; }
            public string NomeProprietario { get; set; }
            public string ModeloVeiculo { get; set; }
        }
    }

    Até aí tudo bem, o meu problema começa agora, pois ainda não compreendi como "dizer" à classe JoinViewModel que o campo CpfProprietário, corresponde ao campo Cpf da tabela Pessoas, NomeProprietário corresponde ao campo Nome da tabela pessoas e ModeloVeículo corresponde ao campo Modelo da tabela Veiculos.

    Abaixo segue o código do Controller da ViewModel:

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Entity;
    using System.Linq;
    using System.Net;
    using System.Web;
    using System.Web.Mvc;
    using TesteViewModel.Models;
    using TesteViewModel.ViewModels;
    
    namespace TesteViewModel.Controllers
    {
        public class JoinViewModelsController : Controller
        {
            private BancoContexto db = new BancoContexto();
    
            // GET: JoinViewModels
            public ActionResult Index()
            {
                return View(db.JoinViewModels.ToList());
            }
    Mais uma vez agradeço pela ajuda!!

    sexta-feira, 28 de agosto de 2015 22:32
  • Faltou este trecho do código, onde executo a consulta linq:

      public ActionResult Index()
            {
    
                var query = from p in db.Pessoas
                            join v in db.Veiculos on p.Cpf equals v.CpfProprietario
                            select new { cpfproprietario = p.Cpf, nomeproprietario = p.Nome, modeloveiculo = v.Modelo };

    Daí em diante eu estou com dificuldade em transferir os dados da query para a instância da classe JoinViewModel

    sexta-feira, 28 de agosto de 2015 23:02
  • É só criar uma view model deste jeito:

    public class Veiculo{
      string cpfproprietario {get;set;}
      string nomeproprietario{get;set;} 
      string modeloveiculo {get;set;}
    }

    e no seu control:

    public ActionResult Index() { var query = from p in db.Pessoas join v in db.Veiculos on p.Cpf equals v.CpfProprietario select new { cpfproprietario = p.Cpf, nomeproprietario = p.Nome, modeloveiculo = v.Modelo }; List<Veiculo> veiculos=new List<Veiculo>(); foreach(Object o in query){ Veiculo veiculo= new Veiculo();

    veiculo.cpfproprietario=o.cpfproprietario;

    veiculo.nomeproprietario=o.nomeproprietario;

    veiculo.modeloveiculo=o.modeloveiculo; veiculos.add(veiculo); } return view(veiculos); }


    É claro que com o automapper a soluçao seria mais elegante, mas deste jeito é mais legivel.

    att


    William John Adam Trindade
    Analyste-programmeur
    ----------------------------------------------------------

    segunda-feira, 31 de agosto de 2015 13:00
    Moderador