« Repository Pattern » : différence entre les versions
Apparence
Page créée avec « Category:.NET Core Category:Patterns = Links = * [https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design#the-repository-pattern Design the infrastructure persistence layer] = Repository Pattern = * 1 {{boxx|Repository}} per resource: {{boxx|ItemRepository}} * 1 {{boxx|DbContext}} for the whole application <filebox fn='Repositories/ItemRepository.cs' collapsed> public cla... » |
Aucun résumé des modifications |
||
Ligne 72 : | Ligne 72 : | ||
return nbAffectedRows == 1; | return nbAffectedRows == 1; | ||
} | } | ||
</filebox> | |||
= [https://blog.dcube.fr/index.php/2019/09/05/generic-repository-unit-of-work-et-entity-framework Generic repository] = | |||
<filebox fn='RepositoryBase.cs' collapsed> | |||
public abstract class RepositoryBase<TEntity, TCreateUpdateQuery> where TEntity : class, new() | |||
{ | |||
private readonly AppContext context; | |||
private DbSet<TEntity> dbEntities { get; } | |||
protected RepositoryBase(BourseContext context) | |||
{ | |||
this.context = context ?? throw new ArgumentNullException(nameof(context)); | |||
dbEntities = this.context.Set<TEntity>(); | |||
} | |||
protected async Task<IReadOnlyCollection<TResult>> GetAsync<TResult>( | |||
Expression<Func<TEntity, TResult>> selector, | |||
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>>? include = null, | |||
Expression<Func<TEntity, bool>>? predicate = null, | |||
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>? orderBy = null, | |||
Func<IQueryable<TEntity>, IQueryable<TEntity>>? skipTake = null, | |||
bool disableTracking = true, | |||
CancellationToken cancellationToken = default) | |||
where TResult : class | |||
{ | |||
IQueryable<TEntity> query = dbEntities; | |||
if (include is not null) | |||
{ | |||
query = include(query); | |||
} | |||
if (predicate is not null) | |||
{ | |||
query = query.Where(predicate); | |||
} | |||
if (orderBy is not null) | |||
{ | |||
query = orderBy(query); | |||
} | |||
if (skipTake is not null) | |||
{ | |||
query = skipTake(query); | |||
} | |||
if (disableTracking) | |||
{ | |||
query = query.AsNoTracking(); | |||
} | |||
return await query.Select(selector).ToListAsync(cancellationToken); | |||
} | |||
public async Task<TEntity> CreateAsync( | |||
TEntity entity, CancellationToken cancellationToken) | |||
{ | |||
ArgumentNullException.ThrowIfNull(entity); | |||
await context.AddAsync(entity, cancellationToken); | |||
await context.SaveChangesAsync(cancellationToken); | |||
return entity; | |||
} | |||
public async Task<bool> UpdateAsync( | |||
Expression<Func<TEntity, bool>> filterByIdExpression, | |||
TCreateUpdateQuery query, | |||
CancellationToken cancellationToken) | |||
{ | |||
ArgumentNullException.ThrowIfNull(query); | |||
var entityToUpdate = await dbEntities | |||
.FirstOrDefaultAsync(filterByIdExpression, cancellationToken); | |||
if (entityToUpdate is null) | |||
{ | |||
return false; | |||
} | |||
UpdateEntityFromCreateUpdateQuery(query, entityToUpdate); | |||
await context.SaveChangesAsync(cancellationToken); | |||
return true; | |||
} | |||
public async Task<bool> DeleteAsync( | |||
Expression<Func<TEntity, bool>> filterByIdExpression, | |||
CancellationToken cancellationToken) | |||
{ | |||
var nbAffectedRows = await dbEntities | |||
.Where(filterByIdExpression) | |||
.ExecuteDeleteAsync(cancellationToken); | |||
return nbAffectedRows > 0; | |||
} | |||
} | |||
</filebox> | </filebox> |
Version du 9 mars 2025 à 11:40
Links
Repository Pattern
- 1 Repository per resource: ItemRepository
- 1 DbContext for the whole application
Repositories/ItemRepository.cs |
public class ItemRepository : IItemRepository
{
private readonly MyAppContext context;
public ItemRepository(MyAppContext context)
{
this.context = context;
}
public async Task<IReadOnlyCollection<Item>> GetAllItemsAsync(CancellationToken cancellationToken)
{
var items = await context.Items
.Include(x => x.NavigationProperty)
.AsNoTracking()
.ToListAsync(cancellationToken);
return items;
}
public async Task<Item?> GetItemByIdAsync(int id, CancellationToken cancellationToken)
{
var item = await context.Items
.AsNoTracking()
.SingleOrDefaultAsync(x => x.Id == id, cancellationToken);
return item;
}
public async Task<IReadOnlyCollection<Item>> GetItemsByNameAsync(string name, CancellationToken cancellationToken)
{
var items = await context.Items
.Where(x => EF.Functions.Like(x.Name, $"%{name}%"))
.AsNoTracking()
.ToListAsync(cancellationToken);
return items;
}
public async Task<Item> CreateItemAsync(Item item, CancellationToken cancellationToken)
{
await context.AddAsync(item, cancellationToken);
await context.SaveChangesAsync(cancellationToken);
return item; // it now contains its id
}
public async Task<bool> UpdateItemAsync(int id, Item item, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(item);
var itemToUpdate = await context.Items.SingleOrDefaultAsync(x => x.Id == id, cancellationToken);
if (itemToUpdate is null)
{
return false; // send not found from controller then
}
itemToUpdate.Name = item.Name;
await context.SaveChangesAsync();
return true;
}
public async Task<bool> DeleteItemAsync(int id, CancellationToken cancellationToken)
{
var nbAffectedRows = await context.Items.Where(x => x.Id == id).ExecuteDeleteAsync(cancellationToken);
return nbAffectedRows == 1;
}
|
Generic repository
RepositoryBase.cs |
public abstract class RepositoryBase<TEntity, TCreateUpdateQuery> where TEntity : class, new()
{
private readonly AppContext context;
private DbSet<TEntity> dbEntities { get; }
protected RepositoryBase(BourseContext context)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
dbEntities = this.context.Set<TEntity>();
}
protected async Task<IReadOnlyCollection<TResult>> GetAsync<TResult>(
Expression<Func<TEntity, TResult>> selector,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>>? include = null,
Expression<Func<TEntity, bool>>? predicate = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>? orderBy = null,
Func<IQueryable<TEntity>, IQueryable<TEntity>>? skipTake = null,
bool disableTracking = true,
CancellationToken cancellationToken = default)
where TResult : class
{
IQueryable<TEntity> query = dbEntities;
if (include is not null)
{
query = include(query);
}
if (predicate is not null)
{
query = query.Where(predicate);
}
if (orderBy is not null)
{
query = orderBy(query);
}
if (skipTake is not null)
{
query = skipTake(query);
}
if (disableTracking)
{
query = query.AsNoTracking();
}
return await query.Select(selector).ToListAsync(cancellationToken);
}
public async Task<TEntity> CreateAsync(
TEntity entity, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(entity);
await context.AddAsync(entity, cancellationToken);
await context.SaveChangesAsync(cancellationToken);
return entity;
}
public async Task<bool> UpdateAsync(
Expression<Func<TEntity, bool>> filterByIdExpression,
TCreateUpdateQuery query,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(query);
var entityToUpdate = await dbEntities
.FirstOrDefaultAsync(filterByIdExpression, cancellationToken);
if (entityToUpdate is null)
{
return false;
}
UpdateEntityFromCreateUpdateQuery(query, entityToUpdate);
await context.SaveChangesAsync(cancellationToken);
return true;
}
public async Task<bool> DeleteAsync(
Expression<Func<TEntity, bool>> filterByIdExpression,
CancellationToken cancellationToken)
{
var nbAffectedRows = await dbEntities
.Where(filterByIdExpression)
.ExecuteDeleteAsync(cancellationToken);
return nbAffectedRows > 0;
}
}
|