-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
88 changed files
with
1,979 additions
and
1,251 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
New/Payeh.SharedKernel/EntityFrameworkCore/Domain/EfCoreReadOnlyRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
using System.Linq.Expressions; | ||
using Microsoft.EntityFrameworkCore; | ||
using Payeh.SharedKernel.Domain; | ||
using Payeh.SharedKernel.Domain.Repositories; | ||
using Payeh.SharedKernel.EntityFrameworkCore.UnitofWork; | ||
using Payeh.SharedKernel.EntityFrameworkCore.UnitOfWork; | ||
|
||
namespace Payeh.SharedKernel.EntityFrameworkCore.Domain; | ||
|
||
/// <summary> | ||
/// Provides a base implementation of a read-only repository for Entity Framework Core. | ||
/// </summary> | ||
/// <typeparam name="TEntity">The type of the entity.</typeparam> | ||
/// <typeparam name="TDbContext">The type of the DbContext.</typeparam> | ||
public abstract class EfCoreReadOnlyRepository<TEntity, TDbContext> : IReadOnlyRepository<TEntity> | ||
where TEntity : Entity | ||
where TDbContext : IPayehDbContext | ||
{ | ||
private readonly IEfCoreDbContextProvider<TDbContext> _databaseProvider; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="EfCoreReadOnlyRepository{TEntity, TDbContext}"/> class. | ||
/// </summary> | ||
/// <param name="databaseProvider">The database provider instance.</param> | ||
protected EfCoreReadOnlyRepository(IEfCoreDbContextProvider<TDbContext> databaseProvider) | ||
{ | ||
_databaseProvider = databaseProvider ?? throw new ArgumentNullException(nameof(databaseProvider)); | ||
} | ||
|
||
/// <summary> | ||
/// Retrieves the DbContext instance, indicating read-only mode. | ||
/// </summary> | ||
/// <returns>The DbContext instance in read-only mode.</returns> | ||
protected async Task<TDbContext> GetDbContextAsync() | ||
{ | ||
return await _databaseProvider.GetDbContextAsync(isReadOnly: true); | ||
} | ||
|
||
/// <summary> | ||
/// Gets the DbSet for the entity. | ||
/// </summary> | ||
protected async Task<DbSet<TEntity>> GetDbSetAsync() | ||
{ | ||
var context = await GetDbContextAsync(); | ||
return context.Set<TEntity>(); | ||
} | ||
|
||
/// <summary> | ||
/// Retrieves an IQueryable for the entity with AsNoTracking enabled. | ||
/// </summary> | ||
/// <returns>An IQueryable for the entity.</returns> | ||
public async Task<IQueryable<TEntity>> GetQueryableAsync() | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return dbSet.AsNoTracking().AsQueryable(); | ||
} | ||
|
||
/// <summary> | ||
/// Finds entities matching the specified predicate. | ||
/// </summary> | ||
public async Task<IEnumerable<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return await dbSet.AsNoTracking().Where(predicate).ToListAsync(); | ||
} | ||
|
||
/// <summary> | ||
/// Finds a single entity matching the specified predicate. | ||
/// </summary> | ||
public async Task<TEntity?> FindOneAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return await PrepareQuery(dbSet).FirstOrDefaultAsync(predicate); | ||
} | ||
|
||
/// <summary> | ||
/// Gets a single entity matching the specified predicate. | ||
/// Throws an exception if the entity is not found. | ||
/// </summary> | ||
public async Task<TEntity> GetOneAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var entity = await FindOneAsync(predicate); | ||
if (entity == null) | ||
{ | ||
throw new InvalidOperationException("Entity not found."); | ||
} | ||
|
||
return entity; | ||
} | ||
|
||
/// <summary> | ||
/// Counts the number of entities matching the specified predicate. | ||
/// </summary> | ||
public async Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return await PrepareQuery(dbSet).CountAsync(predicate); | ||
} | ||
|
||
/// <summary> | ||
/// Checks if any entity exists matching the specified predicate. | ||
/// </summary> | ||
public async Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return await PrepareQuery(dbSet).AnyAsync(predicate); | ||
} | ||
|
||
/// <summary> | ||
/// Prepares a query for the DbSet. Can be overridden to include navigation properties or filters. | ||
/// </summary> | ||
protected virtual IQueryable<TEntity> PrepareQuery(DbSet<TEntity> dbSet) | ||
{ | ||
return dbSet.AsNoTracking(); | ||
} | ||
} |
163 changes: 163 additions & 0 deletions
163
New/Payeh.SharedKernel/EntityFrameworkCore/Domain/EfCoreRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
using System.Linq.Expressions; | ||
using Microsoft.EntityFrameworkCore; | ||
using Payeh.SharedKernel.Domain; | ||
using Payeh.SharedKernel.Domain.Repositories; | ||
using Payeh.SharedKernel.EntityFrameworkCore.UnitofWork; | ||
|
||
namespace Payeh.SharedKernel.EntityFrameworkCore.Domain; | ||
|
||
/// <summary> | ||
/// Provides a base implementation of a repository for Entity Framework Core. | ||
/// </summary> | ||
/// <typeparam name="TEntity">The type of the entity.</typeparam> | ||
/// <typeparam name="TDbContext">The type of the DbContext.</typeparam> | ||
public abstract class EfCoreRepository<TEntity, TDbContext> : IRepository<TEntity> | ||
where TEntity : Entity | ||
where TDbContext : IPayehDbContext | ||
{ | ||
internal IEfCoreDbContextProvider<TDbContext> ContextProvider { get; } | ||
|
||
protected EfCoreRepository(IEfCoreDbContextProvider<TDbContext> contextProvider) | ||
{ | ||
ContextProvider = contextProvider ?? throw new ArgumentNullException(nameof(contextProvider)); | ||
} | ||
|
||
/// <summary> | ||
/// Gets the current DbContext instance. | ||
/// </summary> | ||
protected async Task<TDbContext> GetDbContextAsync() => await ContextProvider.GetDbContextAsync(); | ||
|
||
/// <summary> | ||
/// Gets the DbSet for the entity. | ||
/// </summary> | ||
private async Task<DbSet<TEntity>> GetDbSetAsync() | ||
{ | ||
var context = await GetDbContextAsync(); | ||
return context.Set<TEntity>(); | ||
} | ||
|
||
public async Task<IQueryable<TEntity>> GetQueryableAsync() | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return dbSet.AsQueryable(); | ||
} | ||
|
||
public async Task<IEnumerable<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return await dbSet.Where(predicate).ToListAsync(); | ||
} | ||
|
||
public async Task<TEntity?> FindOneAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return await PrepareQuery(dbSet).FirstOrDefaultAsync(predicate); | ||
} | ||
|
||
public async Task<TEntity> GetOneAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var entity = await FindOneAsync(predicate); | ||
if (entity == null) | ||
{ | ||
throw new InvalidOperationException("Entity not found."); | ||
} | ||
|
||
return entity; | ||
} | ||
|
||
public async Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return await PrepareQuery(dbSet).CountAsync(predicate); | ||
} | ||
|
||
public async Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
return await PrepareQuery(dbSet).AnyAsync(predicate); | ||
} | ||
|
||
public async Task<TEntity> AddAsync(TEntity entity, bool autoSave = false) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
await dbSet.AddAsync(entity); | ||
|
||
if (autoSave) | ||
{ | ||
var context = await GetDbContextAsync(); | ||
await context.SaveChangesAsync(); | ||
} | ||
|
||
return entity; | ||
} | ||
|
||
public async Task UpdateAsync(TEntity entity, bool autoSave = false) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
dbSet.Update(entity); | ||
|
||
if (autoSave) | ||
{ | ||
var context = await GetDbContextAsync(); | ||
await context.SaveChangesAsync(); | ||
} | ||
} | ||
|
||
public async Task DeleteAsync(TEntity entity, bool autoSave = false) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
dbSet.Remove(entity); | ||
|
||
if (autoSave) | ||
{ | ||
var context = await GetDbContextAsync(); | ||
await context.SaveChangesAsync(); | ||
} | ||
} | ||
|
||
public async Task AddRangeAsync(IEnumerable<TEntity> entities, bool autoSave = false) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
await dbSet.AddRangeAsync(entities); | ||
|
||
if (autoSave) | ||
{ | ||
var context = await GetDbContextAsync(); | ||
await context.SaveChangesAsync(); | ||
} | ||
} | ||
|
||
public async Task UpdateRangeAsync(IEnumerable<TEntity> entities, bool autoSave = false) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
dbSet.UpdateRange(entities); | ||
|
||
if (autoSave) | ||
{ | ||
var context = await GetDbContextAsync(); | ||
await context.SaveChangesAsync(); | ||
} | ||
} | ||
|
||
public async Task DeleteRangeAsync(IEnumerable<TEntity> entities, bool autoSave = false) | ||
{ | ||
var dbSet = await GetDbSetAsync(); | ||
dbSet.RemoveRange(entities); | ||
|
||
if (autoSave) | ||
{ | ||
var context = await GetDbContextAsync(); | ||
await context.SaveChangesAsync(); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Prepares a query for the DbSet. Can be overridden to include navigation properties or filters. | ||
/// </summary> | ||
/// <param name="dbSet">The DbSet for the entity.</param> | ||
/// <returns>The prepared query.</returns> | ||
protected virtual IQueryable<TEntity> PrepareQuery(DbSet<TEntity> dbSet) | ||
{ | ||
return dbSet; | ||
} | ||
} |
Oops, something went wrong.