edson dionisio
edson dionisio

Reputation: 31

inherited classes and razor asp.net mvc 5

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

Answers (3)

edson dionisio
edson dionisio

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

Chris Pratt
Chris Pratt

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

Tanveer Badar
Tanveer Badar

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

Related Questions