264 lines
7.2 KiB
C#
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
|
|
} |