|
|
(4 versions intermédiaires par le même utilisateur non affichées) |
Ligne 1 : |
Ligne 1 : |
| [[Category:.NET Core]] | | [[Category:.NET]] |
| = Links = | | = Links = |
| * [https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew What's New in EF Core 8.0] | | * [https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew What's New in EF Core 8.0] |
| * [[Entity_Framework_Plus|Entity Framework Plus]] | | * [[Entity_Framework_Plus|Entity Framework Plus]] |
| * [https://linq2db.github.io/index.html linq2db] | | * [https://linq2db.github.io/index.html linq2db] |
| | * [[Repository_Pattern|Repository Pattern]] |
|
| |
|
| = Entity Framework Core Tools = | | = Entity Framework Core Tools = |
Ligne 179 : |
Ligne 180 : |
|
| |
|
| == [https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding/templates?tabs=dotnet-core-cli Custom Reverse Engineering Templates] == | | == [https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding/templates?tabs=dotnet-core-cli Custom Reverse Engineering Templates] == |
|
| |
| = [https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design#the-repository-pattern Repository Pattern] =
| |
| * 1 {{boxx|Repository}} per resource: {{boxx|ItemRepository}}
| |
| * 1 {{boxx|DbContext}} for the whole application
| |
| <filebox fn='Repositories/ItemRepository.cs' collapsed>
| |
| 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;
| |
| }
| |
| </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>
| |
|
| |
|
| = [https://www.devtrends.co.uk/blog/avoid-asnotracking-and-include-when-querying-using-entity-framework-in-asp.net Avoid using AsNoTracking and Include] = | | = [https://www.devtrends.co.uk/blog/avoid-asnotracking-and-include-when-querying-using-entity-framework-in-asp.net Avoid using AsNoTracking and Include] = |