Hoje veremos como usar o padrão repositório em uma aplicação Blazor Server para exibir os posts de um blog. |
Continuando a primeira parte do artigo vamos implementar o padrão repositório em nosso projeto.
O padrão repositório ou Repository Pattern permite um encapsulamento da lógica de acesso a dados, permitindo o uso da injeção de dependência (DI) e nos levando a uma visão mais orientada a objetos das interações com a camada de acesso a dados.
Usando este padrão, aplicamos em nossa camada de domínio o princípio da persistência ignorante (PI), e assim nossas entidades da camada de negócio, não devem sofrer impactos pela forma como são persistidas no banco de dados.
Os grandes benefícios ao utilizar o padrão repositório são:
Existem diversas formas de implementar o padrão e nesta aula eu vou usar a abordagem clássica e implementar um repositório genérico síncrono.
Implementando o padrão repositório
Vamos criar uma pasta Repositories no projeto e nesta pasta vamos implementar o nosso repositório.
Vamos iniciar criando a interface IRepository<T> onde T é uma classe.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace BlogApp.Repositories
{
public interface IRepository<T> where T : class
{
IEnumerable<T> Get();
IEnumerable<T> Get(Expression<Func<T, bool>> predicate);
T GetId(int id);
T GetById(Expression<Func<T, bool>> predicate);
void Add(T entity);
void Delete(T entity);
void Update(T entity);
}
}
|
Definimos o contrato na interface IRepository, e, embora tenhamos definidos várias assinaturas de métodos neste exemplo eu não vou implementar o CRUD vou apenas exibir dados, mas vou fazer a implementação de todos os métodos para exemplo.
Agora temos que criar a classe Repository que vai implementar essa interface:
using BlogApp.Data;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace BlogApp.Repositories
{
public class Repository<T> : IRepository<T> where T : class
{
private readonly AppDbContext _context;
public Repository(AppDbContext context)
{
_context = context;
}
public void Add(T entity)
{
_context.Set<T>().Add(entity);
}
public void Delete(T entity)
{
_context.Set<T>().Remove(entity);
}
public void Update(T entity)
{
_context.Entry(entity).State = EntityState.Modified;
_context.Set<T>().Update(entity);
}
public IEnumerable<T> Get()
{
return _context.Set<T>().AsEnumerable<T>();
}
public T GetId(int id)
{
return _context.Set<T>().Find(id);
}
public IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
{
return _context.Set<T>().Where(predicate).AsEnumerable<T>();
}
public T GetById(Expression<Func<T, bool>> predicate)
{
return _context.Set<T>().SingleOrDefault(predicate);
}
}
}
|
Note que estamos injetando uma instância do nosso contexto (AppDbContext) no construtor para a seguir usar essa instância e implementar os métodos definidos na interface.
Para poder usar o repositório para as nossas entidades Categoria e Post temos que fazer a implementação específica para essas entidades.
Assim eu poderia começar criando uma classe de Categoria que herda de IRepository<T> mas vamos supor que eu agora precise de um método específico para o Categoria que retorna a lista de categorias pelo nome e outro método específico para Post que retorna todos os Post pelo id da categoria.
Assim vamos criar a interface ICategoriaRepository:
using BlogApp.Data;
using System.Collections.Generic;
namespace BlogApp.Repositories
{
public interface ICategoriaRepository : IRepository<Categoria>
{
IEnumerable<Categoria> GetCategoriasPorNome();
}
}
|
Aqui define o contrato para implementar o método GetCategoriasPorNome() que é específico de Categoria.
Vamos fazer a mesma coisa para Post criando a interface IPostRepository
using BlogApp.Data;
using System.Collections.Generic;
namespace BlogApp.Repositories
{
public interface IPostRepository : IRepository<Post>
{
IEnumerable<Post> GetPostsPorCategoriaId(int id);
}
}
|
Aqui temos a assinatura do método GetPostsPorCategoriaId() que é especifico para Post.
Agora sim podemos implementar o repositório para Categoria e Post criando as classes CategoriaRepository e PostRepository:
1- CategoriaRepository
using BlogApp.Data;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace BlogApp.Repositories
{
public class CategoriaRepository : IRepository<Categoria> , ICategoriaRepository
{
private readonly AppDbContext _context;
public CategoriaRepository(AppDbContext context)
{
_context = context;
}
public void Add(Categoria entity)
{
_context.Categorias.Add(entity);
}
public void Delete(Categoria entity)
{
_context.Categorias.Remove(entity);
}
public IEnumerable<Categoria> Get()
{
return _context.Categorias.AsNoTracking().ToList();
}
public Categoria GetId(int id)
{
return _context.Categorias.Find(id);
}
public void Update(Categoria entity)
{
_context.Categorias.Update(entity);
}
public IEnumerable<Categoria> Get(Expression<Func<Categoria, bool>> predicate)
{
return _context.Categorias.Where(predicate);
}
public Categoria GetById(Expression<Func<Categoria, bool>> predicate)
{
return _context.Categorias.FirstOrDefault(predicate);
}
public IEnumerable<Categoria> GetCategoriasPorNome()
{
return Get().OrderBy(c => c.Nome).ToList();
}
}
}
|
2- PostRepository
using BlogApp.Data;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace BlogApp.Repositories
{
public class PostRepository : IRepository<Post>, IPostRepository
{
private readonly AppDbContext _context;
public PostRepository(AppDbContext context)
{
_context = context;
}
public void Add(Post entity)
{
_context.Posts.Add(entity);
}
public void Delete(Post entity)
{
_context.Posts.Remove(entity);
}
public IEnumerable<Post> Get()
{
return _context.Posts.AsNoTracking().ToList();
}
public Post GetId(int id)
{
return _context.Posts.Find(id);
}
public void Update(Post entity)
{
_context.Posts.Update(entity);
}
public IEnumerable<Post> Get(Expression<Func<Post, bool>> predicate)
{
return _context.Posts.Where(predicate);
}
public Post GetById(Expression<Func<Post, bool>> predicate)
{
return _context.Posts.FirstOrDefault(predicate);
}
public IEnumerable<Post> GetPostsPorCategoriaId(int id)
{
return _context.Posts.Where(p => p.CategoriaId == id);
}
}
}
|
Na figura abaixo temos uma representação das interfaces e classes que foram criadas para implementar o padrão reposítório usando uma abordagem padrão:
Na próxima parte do artigo vamos criar os componentes Blazor para exibir o menu de categorias e os posts relacionados com a categoria selecionada.
Pegue o projeto aqui: BlogApp.zip (sem as referências)
"E se abrires a tua alma ao
faminto, e fartares a alma aflita; então a tua luz
nascerá nas trevas, e a tua escuridão será como o
meio-dia."
Isaías 58:10
ASP .NET Core - Iniciando com o Blazor -
ASP .NET Core - CRUD usando Blazor e Entity ...
Blazor - O novo framework SPA da Microsoft -
ASP .NET Core - Iniciando com o Blazor
ASP .NET Core - CRUD usando Blazor e Entity ... -
Blazor - O novo framework SPA da Microsoft -
Blazor - Vale a pena usar o Blazor
Core - Iniciando com Blazor (.NET Core 3.0) - III -
ASP .NET Core - CRUD usando Blazor e Entity ...
ASP .NET Core Blazor - Gerenciando Usuários e ...
Visual Studio Code - Suporte ao desenvolvimento Blazor