Blazor - CRUD básico com SQLite
Neste tutorial vamos criar uma aplicação Blazor Sserver e realizar o CRUD básico usando o SQLite. |
Vamos
criar uma aplicação simples que vai ler todos os registros da tabela
Produtos dentro de um banco de dados SQLite
ProdutosDB.db. Os registros serão exibidos como uma tabela HTML na interface com
o usuário.
Na interface teremos um botão de exclusão individual é exibido em cada linha, e, clicando no mesmo exclui o registro da tabela Produtos. Ao lado da tabela, é exibido um formulário para adicionar um novo produto à tabela do banco de dados e, da mesma forma, também é exibido um formulário para atualizar o produto, através do qual o usuário pode atualizar um produto existente. Agora vamos implementar a operação CRUD no Blazor usando o SQLite como back-end.
A seguir temos uma visão da aplicação em execução :
recursos usados:
VS 2022
SQLite
.NET 7.0
Criando o projeto
No VS 2022 Community vamos criar um projeto usando o template Blazor Server App com o nome BlazorSqlite.
Após criar o projeto vamos remover as referências e arquivos que não vamos usar e a seguir incluir os seguintes pacotes nugets no projeto:
1-
Microsoft.EntityFrameworkCore.Sqlite
2-
Microsoft.EntityFrameworkCore.Tools
Na pasta Data do projeto vamos criar a classe Produto:
public
class
Produto { public int Id { get; set; } public string? Nome { get; set; } public string? Descricao { get; set; } public double Preco { get; set; } public int Quantidade { get; set; } } |
Na mesma pasta vamos criar a classe de contexto ProdutoContext:
public
class
ProdutoContext :
DbContext { public ProdutoContext(DbContextOptions<ProdutoContext> options): base(options) {} public DbSet<Produto> Produto { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Produto>().HasData(GetProdutos()); base.OnModelCreating(modelBuilder); } private List<Produto> GetProdutos() { return new List<Produto> { new Produto { Id = 1001, Nome = "Laptop", Preco = 20.02, Quantidade = 10, Descricao ="O melhor laptop para jogos"}, new Produto { Id = 1002, Nome = "Microsoft Office", Preco = 20.99, Quantidade = 50, Descricao ="Aplicação Office"}, new Produto { Id = 1003, Nome = "Lazer Mouse", Preco = 12.02, Quantidade = 20, Descricao ="Um mouse decente"}, new Produto { Id = 1004, Nome = "USB Storage", Preco = 5.00, Quantidade = 20, Descricao ="Armazena ate 256GB de dados"} }; } } |
Nesta classe estamos usando o método HasData para incluir 3 registros na tabela quando da aplicação do Migrations.
Agora vamos criar a pasta Services no projeto e a seguir criar a interface IProdutoService e a classe concreta ProdutoService que implementa esta interface :
1- IProdutoService
public
interface
IProdutoService { Task<List<Produto>> GetProdutosAsync(); Task<Produto> AddProdutoAsync(Produto produto); Task<Produto> UpdateProdutoAsync(Produto produto); Task DeleteProdutoAsync(Produto produto); } |
2- ProdutoService
using
BlazorSqlite.Data; using Microsoft.EntityFrameworkCore; namespace BlazorSqlite.Services;public class ProdutoService : IProdutoService{ private readonly ProdutoContext dbContext; public ProdutoService(ProdutoContext dbContext) { this.dbContext = dbContext; } public async Task<List<Produto>> GetProdutosAsync() { return await dbContext.Produto.ToListAsync(); } public async Task<Produto> AddProdutoAsync(Produto produto) { try { dbContext.Produto.Add(produto); await dbContext.SaveChangesAsync(); } catch (Exception) { throw; } return produto; } public async Task<Produto> UpdateProdutoAsync(Produto produto) { try { var productExist = dbContext.Produto.FirstOrDefault(p => p.Id == produto.Id); if (productExist != null) { dbContext.Update(produto); await dbContext.SaveChangesAsync(); } } catch (Exception) { throw; } return produto; } public async Task DeleteProdutoAsync(Produto produto) { try { dbContext.Produto.Remove(produto); await dbContext.SaveChangesAsync(); } catch (Exception) { throw; } } } |
No arquivo _Imports.razor inclua as referências:
... @using BlazorSqlite.Data @using BlazorSqlite.Services |
Na classe Program vamos registrar o serviço e contexto da aplicação :
using
BlazorSqlite.Data; using BlazorSqlite.Services; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args);// Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddDbContext<ProdutoContext>(options => { options.UseSqlite("Data Source = ProdutosDB.db"); }); builder.Services.AddScoped<IProdutoService,
ProdutoService>(); |
Criando o componente Razor
Vamos o componente Razor ProdutosPage na pasta Pages mas antes vamos ajustar o código do arquivo NavMenu.razor da pasta /Shared criando os seguintes links no menu : Home e Produtos :
... <div class="nav-item px-3"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="oi oi-home" aria-hidden="true"></span> Home </NavLink> </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="produtos"> <span class="oi oi-list" aria-hidden="true"></span> Produtos </NavLink> </div> ... |
Na página Index.razor vamos exibir uma imagem produtos1.jpg que esta contida na pasta wwwroot/images:
@page
"/" < h3>Produtos</h3><center> <img src="images/produtos1.jpg" height="424" width="256"/> </center> |
Vamos criar agora componente ProdutosPage.razor que vai exibir a relação de produtos existentes com opção para Deletar os dados de um produto selecionado :
@page "/produtos" @inject IProdutoService service <div class="container"> <div class="row bg-light"> <table class="table table-bordered"> <thead class="thead-dark"> <tr> <th>ID</th> <th>Nome</th> <th>Descrição</th> <th>Preço</th> <th>Quantidade</th> <th>Deletar</th> </tr> </thead> <tbody> @if (Produtos.Any()) { @foreach (var produto in Produtos) { <tr @onclick="(() => SetProdutoForUpdate(produto))"> <td>@produto.Id</td> <td>@produto.Nome</td> <td>@produto.Descricao</td> <td>@produto.Preco</td> <td>@produto.Quantidade</td> <td><button class="btn btn-danger" @onclick="(() => DeleteProduto(produto))">Deletar</button></td> </tr> } } else { <tr><td colspan="6"><strong>Nenhum produto disponível</strong></td></tr> } </tbody> </table> </div> <div class="row m-5"> <div class="col-5 bg-light m-2 justify-content-start"> <div class="p-3 mb-3 bg-primary text-white text-center">Novo Produto</div> <EditForm Model="@NovoProduto"> <div class="form-group"> <label for="nome">Nome</label> <input type="text" id="nome" class="form-control" @bind-value="@NovoProduto.Nome" /> </div> <div class="form-group"> <label for="preco">Preço</label> <input type="text" id="preco" class="form-control" @bind="@NovoProduto.Preco" /> </div> <div class="form-group"> <label for="quantidade">Quantidade</label> <input type="text" id="quantidade" class="form-control" @bind="@NovoProduto.Quantidade" /> </div> <div class="form-group"> <label for="descricao">Descrição</label> <input type="text" id="descricao" class="form-control" @bind="@NovoProduto.Descricao" /> </div> <div class="text-center p-3 mb-3"> <button class="btn btn-info" @onclick="AddNovoProduto"> Adicionar</button> </div> </EditForm> </div> <div class="col-5 bg-light m-2 justify-content-end"> <div class="p-3 mb-3 bg-primary text-white text-center">Atualiza Produto</div> <EditForm Model="@UpdateProduto"> <div class="form-group"> <label for="nome">Nome</label> <input type="text" id="nome" class="form-control" @bind-value="@UpdateProduto.Nome" /> </div> <div class="form-group"> <label for="preco">Preco</label> <input type="text" id="preco" class="form-control" @bind="@UpdateProduto.Preco" /> </div> <div class="form-group"> <label for="quantidade">Quantidade</label> <input type="text" id="quantidade" class="form-control" @bind="@UpdateProduto.Quantidade" /> </div> <div class="form-group"> <label for="descricao">Descricao</label> <input type="text" id="descricao" class="form-control" @bind="@UpdateProduto.Descricao" /> </div> <div class="text-center p-3 mb-3"> <button class="btn btn-info" @onclick="UpdateProdutoData">Atualizar</button> </div> </EditForm> </div> </div> </div> @code { List<Produto> Produtos = new List<Produto>(); protected override async Task OnInitializedAsync() { await RefrescaProdutos(); } private async Task RefrescaProdutos() { Produtos = await service.GetProdutosAsync(); } public Produto NovoProduto { get; set; } = new Produto(); private async Task AddNovoProduto() { await service.AddProdutoAsync(NovoProduto); NovoProduto = new Produto(); await RefrescaProdutos(); } Produto UpdateProduto = new Produto(); private void SetProdutoForUpdate(Produto produto) { UpdateProduto = produto; } private async Task UpdateProdutoData() { await service.UpdateProdutoAsync(UpdateProduto); await RefrescaProdutos(); } private async Task DeleteProduto(Produto produto) { await service.DeleteProdutoAsync(produto); await RefrescaProdutos(); } } |
Aplicando a migração
Vamos agora aplicar o Migrations para gerar o banco de dados ProdutosDB.db a tabela Produtos e incluir os registros.
No VS 2022 abra a janela Package Manager Console e a seguir execute os seguintes comandos nesta ordem:
1- Add-Migration Inicial
2- Update-Database
O primeiro comando vai criar o arquivo de scripts contendo os comandos para criar o banco, a tabela e os registros e o segundo comando vai aplicar este script.
Pegue o código do projeto aqui: BlazorSqlite.zip
"Não vos esqueçais da hospitalidade, porque por ela
alguns, não o sabendo, hospedaram anjos."
Hebreus 13:2
Referências: