c# – Relationships at ViewModel with EF

Question:

I'm developing a project where a user will have lots of data. In order not to extend the class too much, I thought of separating it by categories. Example of classes:

  • User
  • Personal data
  • Family Data
  • Etc.

To do this on the site, I thought about creating a carousel with boostrap and creating a ViewModel to store all the candidate's data:

ex:

public class DadosCandidatoViewModel
{
    public int CandidatoId { get; set; }

    public CandidatoViewModel CandidatoViewModel { get; set; }
    public DadosPessoaisViewModel DadosPessoaisViewModel { get; set; }
    //ETC

}

Then the doubt starts, because I don't even know if it's necessary, since the Candidate Model already has the virtual ones for these tables, as well as these other tables also already have a candidate since the relationship is 1 to 1 or 0.

public class Candidato
{
    public int CandidatoId { get; set; }
    public string Nome { get; set; }
    public string CPF { get; set; }

    public DateTime DataCadastro { get; set; }
    public bool Ativo { get; set; }

    public virtual DadosPessoais DadosPessoais { get; set; }
    public virtual DadosFamiliares DadosFamiliares { get; set; }

    public virtual ICollection<Cargo> Cargos { get; set; }

}

public class DadosPessoais
{
    public int CandidatoId { get; set; }

    public string Sexo { get; set; }
    public string Endereco { get; set; }

    public virtual Candidato Candidato { get; set; }
}

My View Model Looked Like This:

public class CandidatoViewModel
{

    [Key]
    public int CandidatoId { get; set; }

    [Required(ErrorMessage = "Preencher o campo Nome")]
    [MaxLength(150, ErrorMessage = "Máximo {1} caracteres")]
    [MinLength(2, ErrorMessage = "Mínimo {1} caracteres")]
    public string Nome { get; set; }

    [Required(ErrorMessage = "Preencher o campo CPF")]
    [MaxLength(15, ErrorMessage = "Máximo {1} caracteres")]
    [MinLength(2, ErrorMessage = "Mínimo {1} caracteres")]
    //Criar Datatype de CPF
    public string CPF { get; set; }

    [ScaffoldColumn(false)]
    public DateTime DataCadastro { get; set; }

    public virtual DadosPessoaisViewModel DadosPessoais { get; set; }

    public bool Ativo { get; set; }
}


public class DadosPessoaisViewModel
{
    [Required(ErrorMessage = "Preencher o campo Endereço")]
    [MaxLength(1, ErrorMessage = "Máximo {0} caracteres")]
    [MinLength(1, ErrorMessage = "Mínimo {0} caracteres")]
    public string Sexo { get; set; }

    [Required(ErrorMessage = "Preencher o campo Endereço")]
    [MaxLength(500, ErrorMessage = "Máximo {0} caracteres")]
    [MinLength(2, ErrorMessage = "Mínimo {0} caracteres")]
    public string Endereco { get; set; }
}

Well, first I need to know if I'm doing it right, or at least going down the right path, because the way it is I'm facing a lot of problems when it comes to persisting data.

Below is the View I created for the DadosCandidatoViewModel control where I intend to call the Partial Views for Candidate Data:

@model Gestao_RH.MVC.ViewModels.DadosCandidatoViewModel


@{
    ViewBag.Title = "DadosCandidato";
}

<h2>Edit</h2>

<!-- Div na qual o "carousel" será aplicado. -->
<div id="div-carousel" class="carousel slide">
    <div class="carousel-inner">
        <!-- Divs com efeito de transição. -->
        <div class="item active">

            @Html.Partial("~/Views/DadosPessoais/Edit.cshtml", Model)
        </div>
        <div class="item">
            Conteúdo da DIV 2.
        </div>
    </div>
</div>
<div class="row">
    <!-- Botões de navegação -->
    <div id="div-1" class="span2">
        <a id="a-1" class="btn" href="#div-carousel" data-slide="prev"><i class="icon-chevron-left"></i>Voltar para DIV 1</a>
    </div>
    <div id="div-2" class="span2">
        <a id="a-2" class="btn" href="#div-carousel" data-slide="next">Avançar para DIV 2<i class="icon-chevron-right"></i></a>
    </div>
</div>


<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

    <script type="text/javascript">
        $(document).ready(function () {

            // Aplica o efeito de "carousel" nas divs que possuirem a classe carousel.
            $('.carousel').carousel({
                interval: false
            });

            // Oculta o botão de navegação para a div 1.
            $('#div-1').hide();

            // Aplica a transição quando houver click no link AVANÇAR.
            $("#a-1").click(function () {
                $('#div-carousel').carousel(0);
                $('#div-1').hide();
                $('#div-2').show();
                return false;
            });

            // Aplica a transição quando houver click no link VOLTAR.
            $("#a-2").click(function () {
                $('#div-carousel').carousel(1);
                $('#div-1').show();
                $('#div-2').hide();
                return false;
            });
        });
    </script>
}

Below is just an example of the ViewModel that Saves or edits Personal Data:

@model Gestao_RH.MVC.ViewModels.DadosCandidatoViewModel

@using (Html.BeginForm("SaveDadosPessoais", "DadosCandidato", FormMethod.Post, new { }))
{
    @Html.AntiForgeryToken()

    @Html.DisplayFor(model => model.CandidatoViewModel.Nome);
    @Html.HiddenFor(model => model.CandidatoId);

    <div class="form-horizontal">
        <h4>DadosPessoaisViewModel</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.CandidatoId)

        <div class="form-group">
            @Html.LabelFor(model => model.DadosPessoaisViewModel.Sexo, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.DadosPessoaisViewModel.Sexo, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DadosPessoaisViewModel.Sexo, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.DadosPessoaisViewModel.Endereco, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.DadosPessoaisViewModel.Endereco, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DadosPessoaisViewModel.Endereco, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Salvar " class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

This here is also not working:

public class DadosCandidatoController : Controller
{
    //  private readonly ProdutoRepository _ProdutoRepository = new ProdutoRepository();
    private readonly ICandidatoAppService _candidatoApp;
    private readonly IDadosPessoaisAppService _dadosPessoasApp;
    // GET: Produtos

    public DadosCandidatoController(ICandidatoAppService candidatoApp, IDadosPessoaisAppService dadosPessoaisApp)
    {
        _candidatoApp = candidatoApp;
        _dadosPessoasApp = dadosPessoaisApp;
    }


    [HttpGet]
    public ActionResult DadosCandidato(int id)
    {
        var candidato = _candidatoApp.GetById(id);
        var DadosCandidatoViewModel = Mapper.Map<Candidato, DadosCandidatoViewModel>(candidato);


        return View("DadosCandidato", DadosCandidatoViewModel);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult SaveDadosPessoais(DadosCandidatoViewModel model)
    {

        if (ModelState.IsValid)
        {
            var DadosPessoaisDomain = Mapper.Map<DadosPessoaisViewModel, DadosPessoais>(model.DadosPessoaisViewModel);


            if (_dadosPessoasApp.GetById(model.CandidatoId) == null)
            {

                _dadosPessoasApp.Add(DadosPessoaisDomain);
            }
            else
            {
                _dadosPessoasApp.Update(DadosPessoaisDomain);
            }


            return View("DadosCandidato", model);
        }


        return View("DadosCandidato", model);
    }
}

Any help is very welcome, my head is in knots with MVC.

Answer:

If the idea is to separate by ViewModels so that each ViewModel is represented by a Partial , the reasoning is wrong.

The idea of ​​separating Models (or ViewModels ) is for the cardinality principle: normally the separation is for certain associations or aggregations. In your case, there is no need for this separation.

If Models are the same as ViewModels , using ViewModels in your application seems like a nonsense.

You can pretty much define your entire Model like this:

public class Candidato
{
    [Key]
    public int CandidatoId { get; set; }
    public string Nome { get; set; }
    public string CPF { get; set; }

    public DateTime DataCadastro { get; set; }
    public bool Ativo { get; set; }

    public string Sexo { get; set; }
    public string Endereco { get; set; }

    public virtual DadosPessoais DadosPessoais { get; set; }
    public virtual DadosFamiliares DadosFamiliares { get; set; }

    public virtual ICollection<Cargo> Cargos { get; set; }
}

Apparently you are using Automapper to map your ViewModels to Models . I don't know what your App Service layer does, but a tip is to use debug to see what's going on.

Scroll to Top