Reputation: 31
Good morning, I have a problem with returning my database information (generated using the EF 6 code-first method) for my View Razor. The issue is that I'm wanting to return the information from inherited classes in the View, but they are not available, only the properties of the base class are presented, not those of the dependent classes. The following are the Model, Controller, and View classes used:
Class ClientModel
public class Client
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ClientId { get; set; }
[DataType(DataType.Date)]
public DateTime Birth { get; set; }
[Display(Name = "Telefone principal")]
public string Phone1 { get; set; }
[Display(Name = "Telefone Alternativo")]
public string Phone2 { get; set; }
public ICollection<OrcamentoContato> Contacts { get; set; }
public ICollection<Contrato> Contracts { get; set; }
}
Class FisicModel
public class PessoaFisica : Client
{
public TipoPessoa PersonType { get; set; }
[Required]
[Display(Name = "Nome completo*")]
[StringLength(250, ErrorMessage = "O campo é obrigatório.")]
public string Name { get; set; }
public string RG { get; set; }
[Required(ErrorMessage = "O campo CPF é obrigatório.")]
[StringLength(14)]
public string CPF { get; set; }
[Display(Name = "Filiação")]
public string Filiacao { get; set; }
[Display(Name = "Endereço")]
public string Address { get; set; }
}
Class JuridicModel
public class PessoaJuridica : Client
{
public TipoPessoa PersonType { get; set; }
[Required]
[Display(Name = "Razão Social*")]
[StringLength(200, ErrorMessage = "O campo é obrigatório.")]
public string SocialName { get; set; }
[Required]
[Display(Name = "CNPJ*")]
[StringLength(200, ErrorMessage = "O campo é obrigatório.")]
public string CNPJ { get; set; }
[Display(Name = "Inscrição Estadual")]
public string InscricaoEstadual { get; set; }
[Display(Name = "Inscrição Municipal")]
public string InscricaoMunicipal { get; set; }
[Display(Name = "Endereço")]
public string Address { get; set; }
public string ContactWith { get; set; }
}
Controller
public ActionResult Index()
{
var clients = db.Clients.ToList();
return View(clients);
}
Index View
@model IEnumerable<CabinePhoto.Models.Entidades.Client>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Birth)
</th>
<th>
@Html.DisplayNameFor(model => model.Phone1)
</th>
<th>
@Html.DisplayNameFor(model => model.Phone2)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Birth)
</td>
<td>
@Html.DisplayFor(modelItem => item.Phone1)
</td>
<td>
@Html.DisplayFor(modelItem => item.Phone2)
</td>
</tr>
}
IdentityModel
public DbSet<Client> Clients { get; set; }
public DbSet<PessoaFisica> PessoaFisica { get; set; }
public DbSet<PessoaJuridica> PessoaJuridica { get; set; }
All the information is stored in the same client table, since I'm using the form of inheritance by hierarchy, but in the view only the client model information is returned
Upvotes: 1
Views: 1819
Reputation: 31
I've been able to solve the problem. I'll leave here recorded what I did to solve the problem in respect to inheritance.
First, I created a ViewModel and put two ICollection properties, I modified the controller by adding the queries referring to the client table, but specifically bringing the required types and finally, I passed the ViewModel to the Index.cshtml and I used two foreachs to retrieve the information from According to the type specified, shown below:
ClientesiewModel.cs
public class ClientesViewModel
{
public IEnumerable<PessoaFisica> Fisica { get; set; }
public IEnumerable<PessoaJuridica> Juridica { get; set; }
}
controlle.cs
public ActionResult Index()
{
var cliente_fisico = db.Clientes.OfType<PessoaFisica>().ToList();
var cliente_juridico = db.Clientes.OfType<PessoaJuridica>().ToList();
var cliente = db.Clientes.ToList();
ClientesViewModel clientes = new ClientesViewModel()
{
Fisica = cliente_fisico,
Juridica = cliente_juridico
};
return View(clientes);
}
View Index.cshtml
@model CabinePhoto.ViewModels.ClientesViewModel
<table class="table">
<tr>
<th>
@Html.DisplayName("Nome")
</th>
<th>
@Html.DisplayName("Telefone")
</th>
<th>
@Html.DisplayName("Telefone 2")
</th>
<th></th>
</tr>
@if (Model.Fisica != null || Model.Juridica != null)
{
foreach (var fisica in Model.Fisica)
{
<tr>
<td>
@Html.DisplayFor(modelItem => fisica.NomeCompleto)
</td>
<td>
@Html.DisplayFor(modelItem => fisica.TelefonePrincipal)
</td>
<td>
@Html.DisplayFor(modelItem => fisica.TelefoneAlternativo)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = fisica.ClienteId }) |
@Html.ActionLink("Details", "Details", new { id = fisica.ClienteId }) |
@Html.ActionLink("Delete", "Delete", new { id = fisica.ClienteId })
</td>
</tr>
}
foreach (var juridica in Model.Juridica)
{
<tr>
<td>
@Html.DisplayFor(modelItem => juridica.PessoaContato)
</td>
<td>
@Html.DisplayFor(modelItem => juridica.CNPJ)
</td>
<td>
@Html.DisplayFor(modelItem => juridica.TelefonePrincipal)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = juridica.ClienteId }) |
@Html.ActionLink("Details", "Details", new { id = juridica.ClienteId }) |
@Html.ActionLink("Delete", "Delete", new { id = juridica.ClienteId })
</td>
</tr>
}
}
</table>
Thanks for the help previously assigned
Upvotes: 2
Reputation: 239290
Entity Framework actually returns the correct types, but you're effectively upcasting everything to Client
by the variable type you're storing into and the model definition of the view. Essentially, you just need to cast to the right type. Unfortunately, there's no way to just know what type it should be after it's been upcasted. You'll have to conditionally check:
if (item is PessoaFisica)
{
var pessoaFiscica = (PessoaFisica)item;
// now you can access those derived typed properties off of `pessoaFiscica`
}
You can also use as
and rely on the fact that it returns null when something can't be casted:
var pessoaFiscica = item as PessoaFisica;
if (pessoaFiscica != null)
{
// access PessoaFiscica properties
}
With C# 7.0, you can use the pattern matching syntax to streamline it a little:
if (item is PessoaFiscica pessoaFiscica)
{
// use `pessoaFiscica`
}
The pattern matching syntax also allows you use switch blocks, which may make things much easier on you:
switch (item)
{
case PessoaFisica pessoaFisica:
// do something with `PessoaFisica` instance
break;
case PessoaJuridica pessoaJuridica:
// do something with `PessoaJuridica` instance
break;
default:
// do something with generic `Client` instance
break;
}
Upvotes: 0
Reputation: 5523
Suppose you have a variable like this in your controller.
Client c = new Client();
If you later wrote
c.ClientId = 1;
it would work perfectly.
Similarly, if you wrote
PessoaFisica p = new PessoaFisica ();
and later
p.Name = "abc";
it would also work.
However, if you wrote
Client c = new PessoaFisica();
c.Name = "abc";
It will fail to compile.
Along the same lines
@model IEnumerable <CabinePhoto.Models.Entidades.Client>
means static type of your Model
is a collection of Client
objects, it will only allow you to bind to properties defined in Client
class.
Upvotes: 0