Person registration using multiple viewModels and only one controller

Asked

Viewed 2,201 times

2

I want to register a person, which I have divided into three entities: Person, Contact and Address. And I want it to be just a registration form.

My create action in the person controller looks like this:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(PessoaViewModel pessoaViewModel)
    {
          if (ModelState.IsValid)
        {
            pessoaViewModel = _pessoaAppService.Adicionar(pessoaViewModel);          
            return RedirectToAction("Index");
        }

        return View(pessoaViewModel);
    }

Add Method in Application Layer:

public PessoaViewModel Adicionar(PessoaViewModel pessoaViewModel)
    {
        var pessoa = Mapper.Map<PessoaViewModel, Pessoa>(pessoaViewModel);

         BeginTransaction();

        var pessoaValidacao = _pessoaService.Adicionar(pessoa);
        pessoaViewModel = Mapper.Map<Pessoa, PessoaViewModel>(pessoaValidacao);

        Commit();

        return pessoaViewModel;

    }

Add to Domain layer:

 public Pessoa Adicionar(Pessoa pessoa)
    {
        return _pessoaRepositorio.Adicionar(pessoa);
    }

Generic repository:

 public virtual TEntity Adicionar(TEntity obj)
    {
       return DbSet.Add(obj);
    }

And I have some partials views that make the form:

          <!-- todo o formulario-->
            <div class="panel-body">
                <div class="tab-content">

                    <!-- primeira aba -->
                    <div id="tab-1" class="tab-pane active">
                        @Html.Partial("_DadosCadastrais")
                    </div>

                    <!-- segunda aba -->
                    <div id="tab-2" class="tab-pane">
                        @Html.Partial("_Contato")
                    </div>

                    <!-- terceira aba -->
                    <div id="tab-3" class="tab-pane">
                        @Html.Partial("_EnderecoPessoa")
                    </div>

                </div>

and each partial view uses a different viewModel:

contact:

@model V1.Aplicacao.ViewModels.PessoaContatoViewModel

Addressee:

@model V1.Aplicacao.ViewModels.EnderecoViewModel

Person:

@model V1.Aplicacao.ViewModels.PessoaViewModel

How do I use the person create method to register these three entities in the bank?

  • You have 1 person object, and inside it you put the other 2 objects that you want to move from the view to the controller, then just register. From what I understand it can be done like this.

  • Personal Viewmodel can be composed of Personal Contactoviewmodel, Addressmodel and Personal Viewmodel. Use these Personal properties in the partitals.

  • Yes I did, but then in my Personal classappservice, which converts viewModel to entity, how do I do? would be something like : var endereco = Mapper.Map<PessoaViewModel, Endereco>(PessoaViewModel); Pessoa.Enderecos.Add(endereco); Or you don’t have to do that?

  • It will be necessary to declare the mapping rules of Peoplescontactoviewmodel, Addressmodel and Peoplesviewmodel before the rule of Peoplesviewmodel. So Automapper will know how to use them.

2 answers

5

You’re using the Entity Framework wrong. It’s a great opportunity to show why it’s a lousy idea to implement a generic repository and/or service layer.

This:

public PessoaViewModel Adicionar(PessoaViewModel pessoaViewModel)
{
    var pessoa = Mapper.Map<PessoaViewModel, Pessoa>(pessoaViewModel);

    BeginTransaction();

    var pessoaValidacao = _pessoaService.Adicionar(pessoa);
    pessoaViewModel = Mapper.Map<Pessoa, PessoaViewModel>(pessoaValidacao);

    Commit();

    return pessoaViewModel;
}

Subnavigate the Entity Framework, which you use TransactionScope to cover all operations of a transaction.

I don’t know where your context is, but the correct way to persist a series of data supporting rollback that’s how it is:

using (var scope = new TransactionScope()) 
{
    var pessoa = new Pessoa 
    {
        // Converta os campos de PessoaViewModel aqui, ou use alguma
        // outra técnica que preferir. Particularmente não gosto de 
        // AutoMapper.
    };

    context.Pessoas.Add(pessoa);
    context.SaveChanges();

    var pessoaContato = new PessoaContato
    {
        // Mesma coisa aqui, com o seguinte:
        Pessoa = pessoa
    };        

    context.PessoasContatos.Add(pessoaContato);
    context.SaveChanges();

    var endereco = new Endereco
    {
        // Idem
        Pessoa = pessoa
    };        

    context.Enderecos.Add(endereco);
    context.SaveChanges();

    scope.Complete();
}

Although you can say that this code can be encapsulated and reused, there is no need for that, because I can’t imagine another Controller which also includes a person with 2 additional aggregated entities.

  • It’s been a while since I started studying C#, Entity, mvc, etc... there’s a lot I haven’t figured out yet, but I get the way you did, I just don’t quite understand why it’s a bad idea to use generic repository, If I had a lot of tables in the bank and I didn’t use the generic repository, I would have to make one for every entity I had in the bank, wouldn’t that be a bit of code repetition? I’ll take a look at all this and in transactionScope, the tutorials I meet on the internet are a bit confusing sometimes, and thanks for the guidance.

  • 1

    @Aesir Entity Framework already implements a repository. You don’t need to implement another. Look how many times I’ve had to say it.

3

A Viewmodel represents a set of one or more Models and other data that will be represented in a View that needs to display a certain set of information.

Then, you can take advantage and use Personal Contact Information to contemplate the Contact and Address information you want to save.

public class PessoaViewModel
{
   //Todas as propriedades de Pessoa que você deseja utilizar na View...

   //Informações de Endereço...
   public EnderecoViewModel Endereco { get; set; }

   //Informações de Contato...
   public PessoaContatoViewModel Contato { get; set; }
}

Your View should be typed according to your Model, in case Personal (that now contemplates the data of Address and Contact), so that you can access all the information:

@model ...PessoaViewModel

<html>
    <body>
        @using (Html.BeginForm())
        {
            @* seu código da view *@...               
        }
    </body>
</html>

In your Controller, your Post action continues to receive an object from your Personal:

[HttpGet]
public ActionResult Create(PessoaViewModel pessoaViewModel)
{
    if (ModelState.IsValid)
    {

        //Através do objeto pessoaViewModel, você obtem os dados informados 
        //de Pessoa, Endereço e Contato para monta os objetos que deseja salvar.                    
        ...
    } 
    ...
}

Editing:

As doubt of your comment "I don’t know how to do to remove contact data and address from people":

In his Controller, you will receive in the parameter personal all the data of the registration page, so to get the contact data use pessoaViewModel.Contato and pessoaViewModel.Endereco to obtain the address data.

Ex:

//Create a method to return a new person to you

var novaPessoa = _pessoaService.CriarPessoa(pessoaViewModel.Nome, pessoaViewModel.Contato, pessoaViewModel.Endereco);

//Save the person

var pessoaValidacao = _pessoaService.Adicionar(novaPessoa);
  • But then in my Personal classappservice, which converts viewModel to entity, how do I do? would be something like : var endereco = Mapper.Map<PessoaViewModel, Endereco>(PessoaViewModel); Pessoa.Enderecos.Add(endereco);

  • 1

    Sorry, I did not pay attention to the mapping that you are using, even because it was not given the structure of the Person object. Error while mapping Person/Person viewmodel? What is the error message? There are ways you can add your Person class, since it is necessary to know the structure of this class to try to help you in mapping?

  • I did as you said, put the properties I will use and then addressee and contact, It got too big to show here, because I summarized the question.. Not even a mistake, but is not saving in address and contact. I don’t know how to do to remove contact data and address from people;

Browser other questions tagged

You are not signed in. Login or sign up in order to post.