dramaling-vocab-learning/backend/DramaLing.Api/Repositories/BaseRepository.cs

264 lines
7.2 KiB
C#

using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using DramaLing.Api.Data;
using DramaLing.Api.Contracts.Repositories;
namespace DramaLing.Api.Repositories;
/// <summary>
/// 基礎 Repository 實作,提供通用的數據存取邏輯
/// </summary>
/// <typeparam name="T">實體類型</typeparam>
public class BaseRepository<T> : IRepository<T> where T : class
{
protected readonly DramaLingDbContext _context;
protected readonly DbSet<T> _dbSet;
protected readonly ILogger<BaseRepository<T>> _logger;
public BaseRepository(DramaLingDbContext context, ILogger<BaseRepository<T>> logger)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_dbSet = _context.Set<T>();
}
#region
public virtual async Task<T?> GetByIdAsync(object id)
{
try
{
return await _dbSet.FindAsync(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting entity by id: {Id}", id);
throw;
}
}
public virtual async Task<IEnumerable<T>> GetAllAsync()
{
try
{
return await _dbSet.AsNoTracking().ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting all entities of type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual async Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> predicate)
{
try
{
return await _dbSet.AsNoTracking().Where(predicate).ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error finding entities with predicate for type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual async Task<T?> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate)
{
try
{
return await _dbSet.AsNoTracking().FirstOrDefaultAsync(predicate);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting first entity with predicate for type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual async Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate)
{
try
{
return await _dbSet.AnyAsync(predicate);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error checking entity existence for type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual async Task<int> CountAsync(Expression<Func<T, bool>>? predicate = null)
{
try
{
return predicate == null
? await _dbSet.CountAsync()
: await _dbSet.CountAsync(predicate);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error counting entities for type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual async Task<(IEnumerable<T> Items, int TotalCount)> GetPagedAsync(
int pageNumber,
int pageSize,
Expression<Func<T, bool>>? filter = null,
Func<IQueryable<T>, IOrderedQueryable<T>>? orderBy = null)
{
try
{
var query = _dbSet.AsNoTracking();
if (filter != null)
query = query.Where(filter);
var totalCount = await query.CountAsync();
if (orderBy != null)
query = orderBy(query);
var items = await query
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return (items, totalCount);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting paged entities for type {EntityType}, page: {PageNumber}, size: {PageSize}",
typeof(T).Name, pageNumber, pageSize);
throw;
}
}
#endregion
#region
public virtual async Task<T> AddAsync(T entity)
{
try
{
var result = await _dbSet.AddAsync(entity);
return result.Entity;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error adding entity of type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual async Task<IEnumerable<T>> AddRangeAsync(IEnumerable<T> entities)
{
try
{
var entityList = entities.ToList();
await _dbSet.AddRangeAsync(entityList);
return entityList;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error adding entities of type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual Task UpdateAsync(T entity)
{
try
{
_dbSet.Update(entity);
return Task.CompletedTask;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating entity of type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual Task UpdateRangeAsync(IEnumerable<T> entities)
{
try
{
_dbSet.UpdateRange(entities);
return Task.CompletedTask;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating entities of type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual Task DeleteAsync(T entity)
{
try
{
_dbSet.Remove(entity);
return Task.CompletedTask;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting entity of type {EntityType}", typeof(T).Name);
throw;
}
}
public virtual async Task DeleteAsync(object id)
{
try
{
var entity = await GetByIdAsync(id);
if (entity != null)
{
_dbSet.Remove(entity);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting entity by id: {Id} of type {EntityType}", id, typeof(T).Name);
throw;
}
}
public virtual Task DeleteRangeAsync(IEnumerable<T> entities)
{
try
{
_dbSet.RemoveRange(entities);
return Task.CompletedTask;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting entities of type {EntityType}", typeof(T).Name);
throw;
}
}
#endregion
#region
public virtual async Task<int> SaveChangesAsync()
{
try
{
return await _context.SaveChangesAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error saving changes for type {EntityType}", typeof(T).Name);
throw;
}
}
#endregion
}