Person registration using multiple viewModels and only one controller

2

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

My action create 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 the 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

Address:

@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 database?

    
asked by anonymous 20.07.2015 / 20:42

2 answers

5

You are using the Entity Framework incorrectly. It's a great opportunity to show why it's a bad 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;
}

Underaprove the Entity Framework, which uses TransactionScope to cover all operations of a transaction.

I do not know where your context is, but the correct way to persist a rollback is as follows:

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 might say that this code can be encapsulated and reused, there is no need for it , because I can not imagine another Controller that also inserts a person with two more entities added.

    
20.07.2015 / 23:07
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 particular set of information .

So you can take advantage of and use PersonaViewModel to take in 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 the PersonaViewModel case (which now includes the Address and Contact data), so 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 PersonViewModel:

[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 per your question's doubt " I do not know how to remove the contact and redo data from the personViewModel and save in the bank":

In your Controller , you will receive all the data in the registration page in the parameter personViewModel , so to get the contact data use pessoaViewModel.Contato and pessoaViewModel.Endereco to get 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);
    
20.07.2015 / 21:35