Created mappings profiles and repository pattern

This commit is contained in:
2026-02-21 11:08:11 +01:00
parent 3d7400ce89
commit ab6c73cbaa
16 changed files with 476 additions and 40 deletions
+7 -4
View File
@@ -7,6 +7,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.Specification.EntityFrameworkCore" Version="9.3.1" />
<PackageReference Include="AutoMapper" Version="16.0.0" />
<PackageReference Include="AutoMapper.Collection" Version="13.0.0" />
<PackageReference Include="FastEndpoints" Version="7.2.0" />
<PackageReference Include="FastEndpoints.Security" Version="7.2.0" />
<PackageReference Include="FastEndpoints.Swagger" Version="7.2.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.24"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.20" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.20">
@@ -14,11 +20,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.20" />
<PackageReference Include="Plainquire.Page" Version="7.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2"/>
</ItemGroup>
<ItemGroup>
<Folder Include="Repositories\" />
</ItemGroup>
</Project>
@@ -0,0 +1,11 @@
using AutoMapper;
namespace BeReadyBackend.MappingProfiles;
public class DtoToEntityMappings : Profile
{
public DtoToEntityMappings()
{
}
}
@@ -0,0 +1,10 @@
using AutoMapper;
namespace BeReadyBackend.MappingProfiles;
public class EntityToDtoMappings : Profile
{
public EntityToDtoMappings()
{
}
}
+65 -36
View File
@@ -1,44 +1,73 @@
using AutoMapper;
using AutoMapper.EquivalencyExpression;
using BeReadyBackend;
using BeReadyBackend.MappingProfiles;
using FastEndpoints;
using FastEndpoints.Swagger;
using FastEndpoints.Security;
using Microsoft.Net.Http.Headers;
using BeReadyBackend.Repositories;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// On ajoute ici FastEndpoints, un framework REPR et Swagger aux services disponibles dans le projet
builder.Services
.AddAuthenticationJwtBearer(s => s.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong")
.AddAuthorization()
.AddFastEndpoints()
.SwaggerDocument(options =>
{
options.ShortSchemaNames = true;
})
.AddCors(options =>
{
options.AddDefaultPolicy(policyBuilder =>
{
policyBuilder
.WithOrigins("http://localhost:4200")
.WithMethods("GET", "POST", "PUT", "DELETE", "PATCH")
.AllowAnyHeader()
.WithExposedHeaders(HeaderNames.ContentDisposition);
});
});
builder.Services.AddDbContext<BeReadyDbContext>();
builder.Services.AddScoped<AchievementsRepository>();
builder.Services.AddScoped<DesignationsRepository>();
builder.Services.AddScoped<GroupsRepository>();
builder.Services.AddScoped<MessagesRepository>();
builder.Services.AddScoped<RandomChallengesRepository>();
builder.Services.AddScoped<StatusRepository>();
builder.Services.AddScoped<UserAchievementsRepository>();
builder.Services.AddScoped<UserFriendsRepository>();
builder.Services.AddScoped<UserGroupsRepository>();
builder.Services.AddScoped<UserRandomChallengesRepository>();
builder.Services.AddScoped<UsersRepository>();
MapperConfiguration mappingConfig = new(mc =>
{
mc.AddCollectionMappers();
mc.AddProfile(new DtoToEntityMappings());
mc.AddProfile(new EntityToDtoMappings());
}, new LoggerFactory());
AutoMapper.IMapper mapper = mappingConfig.CreateMapper();
builder.Services.AddSingleton(mapper);
WebApplication app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthentication()
.UseAuthorization()
.UseFastEndpoints(options =>
{
options.Endpoints.ShortNames = true;
options.Endpoints.RoutePrefix = "API";
})
.UseSwaggerGen();
app.UseHttpsRedirection();
string[] summaries =
[
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
];
app.UseCors();
app.MapGet("/weatherforecast", () =>
{
WeatherForecast[] forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();
app.Run();
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
app.Run();
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class AchievementsRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<Achievement>(beReadyDbContext, mapper);
@@ -0,0 +1,328 @@
using System.Linq.Expressions;
using Ardalis.Specification;
using Ardalis.Specification.EntityFrameworkCore;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
using Plainquire.Page;
namespace BeReadyBackend.Repositories;
public class BeReadyRepository<T>(DbContext databaseContext, AutoMapper.IMapper mapper) : RepositoryBase<T>(databaseContext) where T : class
{
private readonly DbContext _databaseContext = databaseContext;
/// <summary>
///
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<T?> FirstOrDefaultAsync(CancellationToken cancellationToken = default)
{
return await _databaseContext.Set<T>().AsQueryable().FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<T> FirstAsync(CancellationToken cancellationToken = default)
{
return await _databaseContext.Set<T>().AsQueryable().FirstAsync(cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<T> SingleAsync(ISpecification<T> specification, CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SingleAsync(cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<T> SingleAsync(CancellationToken cancellationToken = default)
{
return await _databaseContext.Set<T>().AsQueryable().SingleAsync(cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="selector"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<int> SumAsync(
ISpecification<T> specification,
Expression<Func<T, int>> selector,
CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SumAsync(selector, cancellationToken);
}
// /// <summary>
// ///
// /// </summary>
// /// <param name="specification"></param>
// /// <param name="selector"></param>
// /// <param name="cancellationToken"></param>
// /// <returns></returns>
// public async Task<int> SumAsync(
// ISpecification<T> specification,
// Expression<Func<T, int>> selector,
// CancellationToken cancellationToken = default)
// {
// return await ApplySpecification(specification).SumAsync(selector, cancellationToken);
// }
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="cancellationToken"></param>
/// <param name="postProcessor"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<TResult?> ProjectToSingleOrDefaultAsync<TResult>(
ISpecification<T> specification,
CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification)
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.SingleOrDefaultAsync(cancellationToken: cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="cancellationToken"></param>
/// <param name="postProcessor"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<TResult?> ProjectToSingleOrDefaultAsync<TResult>(
ISpecification<T> specification,
Action<TResult?> postProcessor,
CancellationToken cancellationToken = default)
{
TResult? result = await ApplySpecification(specification)
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.SingleOrDefaultAsync(cancellationToken: cancellationToken);
postProcessor(result);
return result;
}
// /// <summary>
// ///
// /// </summary>
// /// <param name="cancellationToken"></param>
// /// <typeparam name="TResult"></typeparam>
// /// <returns></returns>
// public async Task<TResult?> ProjectToSingleOrDefaultAsync<TResult>(
// CancellationToken cancellationToken = default)
// {
// return await _databaseContext.Set<T>().AsQueryable().ProjectTo<TResult>(mapper.ConfigurationProvider).SingleOrDefaultAsync(cancellationToken: cancellationToken);
// }
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<TResult> ProjectToSingleAsync<TResult>(
ISpecification<T> specification,
CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification)
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.SingleAsync(cancellationToken: cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="postProcessor"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<TResult> ProjectToSingleAsync<TResult>(
ISpecification<T> specification,
Action<TResult?> postProcessor,
CancellationToken cancellationToken = default)
{
TResult result = await ApplySpecification(specification)
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.SingleAsync(cancellationToken: cancellationToken);
postProcessor(result);
return result;
}
/// <summary>
///
/// </summary>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<TResult> ProjectToSingleAsync<TResult>(
CancellationToken cancellationToken = default)
{
return await _databaseContext.Set<T>()
.AsQueryable()
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.SingleAsync(cancellationToken: cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<List<TResult>> ProjectToListAsync<TResult>(
CancellationToken cancellationToken = default)
{
return await _databaseContext.Set<T>()
.AsQueryable()
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken: cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="postProcessor"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<List<TResult>> ProjectToListAsync<TResult>(
Action<List<TResult>> postProcessor,
CancellationToken cancellationToken = default)
{
List<TResult> results = await _databaseContext.Set<T>()
.AsQueryable()
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken: cancellationToken);
postProcessor(results);
return results;
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="postProcessor"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<List<TResult>> ProjectToListAsync<TResult>(
ISpecification<T> specification,
Action<List<TResult>> postProcessor,
CancellationToken cancellationToken = default)
{
List<TResult> results = await ApplySpecification(specification)
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken: cancellationToken);
postProcessor(results);
return results;
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<List<TResult>> ProjectToListAsync<TResult>(
ISpecification<T> specification,
CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification)
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken: cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="page"></param>
/// <param name="postProcessor"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<List<TResult>> ProjectToListAsync<TResult>(
ISpecification<T> specification,
EntityPage page,
Action<List<TResult>> postProcessor,
CancellationToken cancellationToken = default)
{
List<TResult> results = await ApplySpecification(specification)
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.Page(page)
.ToListAsync(cancellationToken: cancellationToken);
postProcessor(results);
return results;
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="page"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<List<TResult>> ProjectToListAsync<TResult>(
ISpecification<T> specification,
EntityPage page,
CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification)
.ProjectTo<TResult>(mapper.ConfigurationProvider)
.Page(page)
.ToListAsync(cancellationToken: cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="selector"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<List<TResult>> SelectManyAsync<TResult>(
ISpecification<T> specification,
Expression<Func<T, IEnumerable<TResult>>> selector,
CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).SelectMany(selector).ToListAsync(cancellationToken: cancellationToken);
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <param name="selector"></param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public async Task<List<TResult>> SelectAsync<TResult>(
ISpecification<T> specification,
Expression<Func<T, TResult>> selector,
CancellationToken cancellationToken = default)
{
return await ApplySpecification(specification).Select(selector).ToListAsync(cancellationToken: cancellationToken);
}
}
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class DesignationsRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<Designation>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class GroupsRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<Group>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class MessagesRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<Message>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class RandomChallengesRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<RandomChallenge>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class StatusRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<Status>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class UserAchievementsRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<UserAchievement>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class UserFriendsRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<UserFriend>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class UserGroupsRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<UserGroup>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class UserRandomChallengesRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<UserRandomChallenge>(beReadyDbContext, mapper);
@@ -0,0 +1,5 @@
using BeReadyBackend.Models;
namespace BeReadyBackend.Repositories;
public class UsersRepository(BeReadyDbContext beReadyDbContext, AutoMapper.IMapper mapper) : BeReadyRepository<User>(beReadyDbContext, mapper);