Blazor - Acesso ao PostgreSQL com filtro de dados
Hoje veremos como acessar o PostgreSql e implementar um filtro de dados básico. |
Existem muitos componentes prontos que podemos usar para implementar um filtro de dados e neste artigo veremos uma implementação básica.
|
No projeto exemplo vamos usar o EF Core Code-First para acessar e criar uma base de dados no PostgreSQL e a seguir vamos popular o banco com dados iniciais e a seguir vamos implementar uma busca parcial.
Criando o projeto no VS 2022
Abra o VS 2022 e clique em New Project e a seguir selecione o template Blazor Server App e informe o nome Blazor_Search :
A seguir defina as configurações conforme abaixo e clique em Create:
Vamos limpar o projeto removendo os componentes Counter.razor, FetchData.razor, SurveyPrompt.razor e o conteúdo da pasta Data do projeto.
Temos que incluir no projeto os seguintes pacotes usando o comando : install-package <nome>
O primeiro permite acessar o banco PostgreSQL e o seguinte compartilha componentes com a ferramenta que realiza o Migrations.
Agora vamos verificar se temos a ferramenta EF Core Tools instalada usando o comando em um terminal: dotnet ef
Se a ferramenta
não estiver instalada o comando para instalar é o seguinte:
dotnet
tool install
--global dotnet-ef
Com a ferramenta instalada podemos prosseguir.
No arquivo Index.razor vamos definir o código abaixo que vai ser a página de apresentação da aplicação e que vai exibir apenas uma imagem:
@page "/" <PageTitle>Index</PageTitle> < h1>Search Example</h1>
|
No arquivo NavMenu.razor vamos ajustar o código para exibir dois itens no menu: Home e Products
.. <div class="@NavMenuCssClass" @onclick="ToggleNavMenu"> <nav class="flex-column"> <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="products"> <span class="oi oi-plus" aria-hidden="true"></span> Products </NavLink> </div> </nav> </div> .. |
Vamos incluir na pasta wwwroot do projeto a imagem Spinner-2.gif que iremos usar para indicar uma operação em andamento.
Na pasta Data do projeto vamos criar a classe Product com o código:
public
class
Product { public int Id { get; set; }[MaxLength(100)] public string? Name { get; set; } public decimal Price { get; set; } public int Stock { get; set; } } |
A classe Product define 4 propriedades que iremos preencher com dados iniciais para exibir no projeto.
Vamos criar a classe de contexto AppDbContext que herda de DbContext e define o mapeamento ORM entre a entidade Product e a tabela Products e onde usamos o método HasData() para preencher a tabela Products com dados iniciais:
public class
AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) :base(options) {} public DbSet<Product>? Products { get; set; }
protected
override void OnModelCreating(ModelBuilder modelBuilder) |
Vamos incluir no arquivo appsettings.json a string de conexão para acessar o banco de dados PostgreSql:
{ "ConnectionStrings": { "Defaultconnection": "User ID=postgres;Password=***;Host=localhost;Port=5432;Database=CadastroDB;Pooling=true;" }, ... |
Definimos o banco de dados CadastroDB, o usuário e a senha para acessar o banco de dados.
No arquivo _Imports.razor vamos definir o código que será usado pelos componentes:
@using System.Net.Http @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop @using Blazor_Search @using Blazor_Search.Shared @using Blazor_Search.Data |
Vamos registrar o contexto do EF Core definido no arquivo AppDbContext no container DI incluindo na classe Program o código abaixo:
... var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<AppDbContext>(options => ... |
Podemos aplicar o Migrations usando os comandos abaixo na janela do Package Manager Console:
- dotnet ef migrations add Inicial
- dotnet database update
O primeiro criar o arquivo de script com o código para criar as tabelas e popular as tabelas com os dados. O segundo aplicar esse script no banco de dados.
Podemos conferir os dados no PostgreSQL abrindo o pgAdmin:
Vemos a tabela Products do banco de dados CadastroDB preenchida com os dados definidos no arquivo de contexto.
Criando o Serviço para acessar os dados
Vamos criar na pasta Data o serviço que vai permitir obter os dados no PostgreSQL. Para isso vamos criar a interface IProductService e classe ProductService que implementa esta interface :
1- IProductService
public interface IProductService { Task<IEnumerable<Product>> GetAllProducts(); Task<IEnumerable<Product>> GetProductByName(string name); } |
2- ProductService
public class
ProductService : IProductService { protected readonly AppDbContext _context;
public
ProductService(AppDbContext context) |
Neste serviço implementamos dois métodos :
1- GetAllProducts() que retorna uma lista com todos os produtos
2- GetProductByName(string name) que retorna uma lista de objetos que atendem ao critério de conter parte do critério de filtro definido em name;
Criando o componente para exibir os produtos
Na pasta Shared vamos criar dois componentes de suporte que iremos usar no projeto:
1- DisplayError.razor - Exibe mensagens de erros
<h3 class="text-danger"><b>@MensagemErro</b></h3>
@code {
|
2- DisplaySpinner.razor - Exibe a imagem do spinner
<img src="/Spinner-2.gif" /> |
Agora na pasta Pages vamos criar o componente ListProducts.razor :
@page "/products" @inject IProductService productService <h3>Products</h3> <hr /> @if (Products == null &&
ErrorMessage == null)
@foreach (var item in @Products) @code {
Product produto = new Product();
protected async void FilterProduct()
protected async override Task OnInitializedAsync() |
Vamos entender o código:
No inicio estamos injetando uma dependência IProductService, que nos permitirá usar a instância do serviço e acessar os dados;
Criamos o botão com o texto para o usuário submeter o filtro usando o evento onclick e chamando o método FilterProduct.
Estamos usando os componentes DisplaySpinner e DisplayError para exibir o spinner e algum erro que ocorra.
Montamos uma tabela HTML para exibir os dados dos produtos que estão sendo obtidos no método OnInitializedAsync.
No método FilterProduct usamos o método GetProductByName invocado a partir do serviço para filtrar os dados. Neste método estamos usando o método StateHasChanged() para indicar que o estado do componente foi alterado e assim atualizar a interface do usuário.
Agora é só alegria...
Executando o projeto teremos o seguinte resultado:
Pegue o projeto aqui: Blazor_Search.zip (sem as referências)
"E se alguém ouvir
as minhas palavras, e não crer, eu não o julgo; porque eu vim, não para julgar o
mundo, mas para salvar o mundo."
João 12:47
Referências: