ASP.NET Core - CRUD com Master-Detail - II


  Hoje vamos continuar a série de artigos onde veremos como realizar as operações CRUD em um contexto mestre-detalhes em uma aplicação ASP.NET Core.

Continuando a primeira parte do artigo vamos continuar criando a ViewModel e o controlador TimesController e seus métodos Action.

Criando a View Model e o controlador TimesController

Na pasta Models do projeto vamos criar a View Model MasterDetailViewModel :

public class MasterDetailViewModel
{
 
public List<Time>? Times { get; set; }
 
public Time? SelectedTime { get; set; }
 
public Membro? SelectedMembro { get; set; }
 
public EntradaDados EntradaDados { get; set; }
 
public ModoExibicao ModoExibicao { get; set; }
}

Vamos entender o código:

Vamos agora criar um controlador chamado TimesController na pasta Controllers que será responsável por realizar o CRUD na tabela Times.

Iniciamos injetando uma instância do contexto - AppDbContext -  no construtor do controlador e definindo o método Action List :

public class TimesController : Controller
{
   private readonly AppDbContext db;
  
public TimesController(AppDbContext db)
   {
    
this.db = db;
   }
 
 public IActionResult List()
   {
      MasterDetailViewModel model =
new()
      {
           Times = db.Times.ToList(),
           SelectedTime =
null,
           SelectedMembro =
null,
           EntradaDados = EntradaDados.Times,
           ModoExibicao = ModoExibicao.Read
      };
     
return View("Main", model);
    }
}

Nota: Para simplificar não criamos uma camada de acesso aos dados em um Repositório. Isso pode ser feito em uma segunda etapa.

Neste código criamos um objeto MasterDetailViewModel e preenchemos suas propriedades. Especialmente a propriedade Times é importante porque é usada na exibição para renderizar a grade mestre exibindo os times.

A Action List retorna a View Main que iremos criar mais adiante. Esta view  vai renderizar a lista de equipes conforme abaixo:

A seguir vamos criar a Action Select que será usada para selecionar um time quando o usuário clicar no botão - Gerenciar Time :

[HttpPost]
public IActionResult Select(int timeId)
{
   MasterDetailViewModel model =
new()
   {
     Times = db.Times.ToList(),
     SelectedTime = db.Times.Find(timeId),
     SelectedMembro =
null,
     EntradaDados = EntradaDados.Times,
     ModoExibicao = ModoExibicao.Read
   };
  
return View("Main", model);
}

Esta Action recebe o parâmetro de rota timeId e define um objeto MasterDetailViewModel onde estamos agora definindo o time selecionado usando o id do time recebido e e o método Find() para localizar a entidade. Como as entidades estão sendo rastradas pelo contexto a busca será feita na memória e o resultado obtido imediatamente sem ir ao banco de dados.

A seguir vamos criar mais dois métodos Actions   InsertEntry e InsertSave para permitir a inclusão de um novo time.

[HttpPost]
public IActionResult InsertEntry()
{
   MasterDetailViewModel model =
new()
   {
     Times = db.Times.ToList(),
     SelectedTime =
null,
     SelectedMembro =
null,
     EntradaDados = EntradaDados.Times,
     ModoExibicao = ModoExibicao.Insert
   };
  
return View("Main", model);
}

[HttpPost]
public IActionResult InsertSave(Time time)
{
   db.Times.Add(time);
   db.SaveChanges();
   MasterDetailViewModel model =
new()
   {
     Times = db.Times.ToList(),
     SelectedTime = db.Times.Find(time.TimeId),
     SelectedMembro =
null,
     EntradaDados = EntradaDados.Times,
      ModoExibicao = ModoExibicao.Read
   };
  
return View("Main", model);
}

A Action InsertEntry() é invocada quando você clica no botão Inserir Time da grade principal. A seguir, definimos a EntradaDados como Times porque estamos adicionando um novo Team. Também definimos o ModoExibicao como Insert porque queremos renderizar a interface do usuário como esta:

Após inserir os detalhes do time, como Nome e Descrição, e clica em Salvar, a ação InsertSave() será chamada.

No seu código, usamos o método Add() e SaveChanges() para adicionar uma nova equipe. Em seguida, definimos a equipe recém-adicionada como o item selecionado na grade principal. Isso é feito definindo a propriedade SelectedTime do objeto MasterDetailViewModel e ModoExibicao é alterado para o valor Read.

A seguir vamos criar duas Actions UpdateEntry() e UpdateSave() para realizar as operações de atualização :

[HttpPost]
public IActionResult UpdateEntry(int timeId)
{
   MasterDetailViewModel model =
new()
   {
      Times = db.Times.ToList(),
      SelectedTime = db.Times.Find(timeId),
      SelectedMembro =
null,
      EntradaDados = EntradaDados.Times,
      ModoExibicao = ModoExibicao.Update
    };
   
return View("Main", model);
}

[HttpPost]
public IActionResult UpdateSave(Time time)
{
   db.Times.Update(time);
   db.SaveChanges();
   MasterDetailViewModel model =
new()
   {
      Times = db.Times.ToList(),
      SelectedTime = time,
      SelectedMembro =
null,
      EntradaDados = EntradaDados.Times,
      ModoExibicao = ModoExibicao.Read
    };
   
return View("Main", model);
}

A Action UpdateEntry() é invocada quando você clica no botão Editar. Passamos o parâmetro de rota timeId para esta Action e a seguir buscamos esse Time específico e definimos a propriedade SelectedTime de MasterDetailViewModel. Também definimos o ModoExibicao como Update, pois queremos renderizar a interface do usuário para atualização:

Quando você edita um registro de um Time e clica no botão Salvar, a Action UpdateSave() é chamada. Nela, usamos os métodos Update() e SaveChanges() para atualizar esse registro do time. Em seguida, alternamos o ModoExibicao para Read porque a operação de edição acabou.

A seguir vamos definir a Action Delete para deletar um time selecionado

[HttpPost]
public IActionResult Delete(int timeId)
{
  Time time = db.Times.Find(timeId);
  db.Times.Remove(time);
  db.SaveChanges();
  MasterDetailViewModel model =
new()
  {
     Times = db.Times.ToList(),
     SelectedTime =
null,
     SelectedMembro =
null,
     EntradaDados = EntradaDados.Times,
     ModoExibicao = ModoExibicao.Read
   };

   return
View("Main", model);
}

Neste codigo encontramos o Time a ser deletado e então utilizamos os métodos Remove() e SaveChanges() para deletar aquele registro. Como o registro agora foi excluído, também definimos a propriedade SelectedTime de MasterDetailViewModel como nula.

Se você decidir cancelar a operação e retornar pode clicar no botão Cancelar que irá acionar a Action CancelEntry() :

[HttpPost]
public IActionResult CancelEntry(int timeId)
{

   MasterDetailViewModel model = new()
   {
     Times = db.Times.ToList(),
     SelectedTime = db.Times.Find(timeId),
     SelectedMembro =
null,
     EntradaDados = EntradaDados.Times,
     ModoExibicao = ModoExibicao.Read
    };
   
return View("Main", model);
}

Finalmente para cancelar a seleção do Time vamos criar a Action CancelSelection :

[HttpPost]
public IActionResult CancelSelection()
{
   MasterDetailViewModel model =
new()
   {
      Times = db.Times.ToList(),
      SelectedTime =
null,
      SelectedMembro =
null,
      EntradaDados = EntradaDados.Times,
      ModoExibicao = ModoExibicao.Read
   };
  
return View("Main", model);
}

Neste código definimos a propriedade SelectedTime como null.

Isso conclui o controlador TimesController, note que para simplificar não prestamos muita atenção à validação do modelo e ao tratamento de erros. Você pode adicionar esses recursos usando atributos de validação de dados como faria normalmente em qualquer aplicativo ASP.NET Core.

Observe que com exceção do método Action List que é um HttpGet os demais métodos Actions são todos HttpPost e estão postando dados para o servidor.

Na próxima parte vamos continuar tratando do gerenciamento das informações dos membros.

"...O sumo sacerdote lhe tornou a perguntar, e disse-lhe: És tu o Cristo, Filho do Deus Bendito?
E Jesus disse-lhe: Eu o sou, e vereis o Filho do homem assentado à direita do poder de Deus, e vindo sobre as nuvens do céu."
Marcos 14:61-62

Referências:


José Carlos Macoratti