Question:
I'm trying to implement a person registration where I have inheritances for natural and legal person, but my save method is not receiving the person type properly.
follow example code
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Salvar(PessoaViewModel model)
{
if (ModelState.IsValid)
{
if (model is PessoaFisicaViewModel)
await SalvarPessoaFisica(context, model as PessoaFisicaViewModel);
else if (model is PessoaJuridicaViewModel)
await SalvarPessoaJuridica(context, model as PessoaJuridicaViewModel);
else await SalvarPessoa(context, model);
await context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(model);
}
when I click on the save of an individual or legal entity, my method is receiving as it always was the Person type, never the inheritance.
person.cshtml
@model PessoaViewModel
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
@if (Model.PessoaId > 0)
{
<label>Edição da pessoa - @Model.Nome</label>
}
else
{
<label>Cadastro de pessoa</label>
}
</div>
<div class="panel-body">
@using (Html.BeginForm("Salvar", "Pessoa"))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
if (Model is PessoaFisicaViewModel)
{
@Html.Partial("_PessoaFisica", Model)
}
else if (Model is PessoaJuridicaViewModel)
{
@Html.Partial("_PessoaJuridica", Model)
}
else
{
@Html.Partial("_Pessoa", Model)
}
<div class="row">
<div class="col-lg-12">
<a href="@Url.Action("Index")" class="btn btn-default"><i class="fa fa-arrow-left fa-fw"></i> Voltar</a>
<button type="submit" class="btn btn-primary"><i class="fa fa-save fa-fw"></i> Salvar</button>
</div>
</div>
}
</div>
</div>
</div>
</div>
@section scripts {
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/bundles/ajax")
}
_PessoaFisica.cshtml
@model PessoaFisicaViewModel
@Html.HiddenFor(a => a.PessoaId)
@Html.HiddenFor(a => a.Ativo)
<div class="row form-group">
<div class="col-lg-4">
@Html.LabelFor(model => model.CpfCnpj, htmlAttributes: new { @class = "control-label" })
@Html.EditorFor(model => model.CpfCnpj, new { htmlAttributes = new { @class = "form-control", @autofocus = "" } })
@Html.ValidationMessageFor(model => model.CpfCnpj, "", new { @class = "text-danger" })
</div>
</div>
<div class="row form-group">
<div class="col-lg-4">
@Html.LabelFor(model => model.Nome, htmlAttributes: new { @class = "control-label" })
@Html.EditorFor(model => model.Nome, new { htmlAttributes = new { @class = "form-control", @autofocus = "" } })
@Html.ValidationMessageFor(model => model.Nome, "", new { @class = "text-danger" })
</div>
</div>
<div class="row form-group">
<div class="col-lg-4">
@Html.LabelFor(model => model.RgNumero, htmlAttributes: new { @class = "control-label" })
@Html.EditorFor(model => model.RgNumero, new { htmlAttributes = new { @class = "form-control", @autofocus = "" } })
@Html.ValidationMessageFor(model => model.RgNumero, "", new { @class = "text-danger" })
</div>
</div>
_Person Legal.cshtml
@model PessoaViewModel
@Html.HiddenFor(a => a.PessoaId)
@Html.HiddenFor(a => a.Ativo)
<div class="row form-group">
<div class="col-lg-4">
@Html.LabelFor(model => model.CpfCnpj, htmlAttributes: new { @class = "control-label" })
@Html.EditorFor(model => model.CpfCnpj, new { htmlAttributes = new { @class = "form-control", @autofocus = "" } })
@Html.ValidationMessageFor(model => model.CpfCnpj, "", new { @class = "text-danger" })
</div>
</div>
<div class="row form-group">
<div class="col-lg-4">
@Html.LabelFor(model => model.Nome, htmlAttributes: new { @class = "control-label" })
@Html.EditorFor(model => model.Nome, new { htmlAttributes = new { @class = "form-control", @autofocus = "" } })
@Html.ValidationMessageFor(model => model.Nome, "", new { @class = "text-danger" })
</div>
<div class="row form-group">
<div class="col-lg-4">
@Html.LabelFor(model => (model as PessoaJuridicaViewModel).NomeFantasia, htmlAttributes: new { @class = "control-label" })
@Html.EditorFor(model => (model as PessoaJuridicaViewModel).NomeFantasia, new { htmlAttributes = new { @class = "form-control", @autofocus = "" } })
@Html.ValidationMessageFor(model => (model as PessoaJuridicaViewModel).NomeFantasia, "", new { @class = "text-danger" })
</div>
</div>
</div>
<div class="row form-group">
<div class="col-lg-4">
@Html.LabelFor(model => (model as PessoaJuridicaViewModel).InscricaoMunicipal, htmlAttributes: new { @class = "control-label" })
@Html.EditorFor(model => (model as PessoaJuridicaViewModel).InscricaoMunicipal, new { htmlAttributes = new { @class = "form-control", @autofocus = "" } })
@Html.ValidationMessageFor(model => (model as PessoaJuridicaViewModel).InscricaoMunicipal, "", new { @class = "text-danger" })
</div>
</div>
Models
public interface IPessoa
{
bool Ativo { get; set; }
string CpfCnpj { get; set; }
string Nome { get; set; }
int PessoaId { get; set; }
}
public class PessoaViewModel : IPessoa
{
public bool Ativo { get; set; }
public string CpfCnpj { get; set; }
public string Nome { get; set; }
public int PessoaId { get; set; }
}
public interface IPessoaFisica : IPessoa
{
int? RgNumero { get; set; }
}
public class PessoaFisicaViewModel : PessoaViewModel, IPessoaFisica
{
public int? RgNumero { get; set; }
}
public interface IPessoaJuridica : IPessoa
{
string InscricaoMunicipal { get; set; }
string NomeFantasia { get; set; }
}
public class PessoaJuridicaViewModel : PessoaViewModel, IPessoaJuridica
{
public string InscricaoMunicipal { get; set; }
public string NomeFantasia { get; set; }
}
Answer:
The modeling is okay, but I don't understand why ViewModels are treated like Models in your system.
If the generation of the database is correct, there will be a table Pessoas
in all fields combined PessoaFisica
and PessoaJuridica
plus a column called Discriminator
, which indicates what type of entity, whether physical or legal.
In the case of Action Salvar
, then you should use a ViewModel with all fields from both classes, and assemble the object corresponding to the person's type in Controller , and not send the primitive object to the Controller and try to convert. Field binding is done on top of the class placed as an Action argument, and it doesn't understand inheritance. That's why you don't have the values when converting the object.