27 changed files with 534 additions and 71 deletions
@ -0,0 +1,28 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Expressions; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using TaskManager.Entity; |
||||
|
using TaskManager.EntityFramework.Repository; |
||||
|
|
||||
|
namespace TaskManager.EntityFramework |
||||
|
{ |
||||
|
public interface IRepository<TEntity> where TEntity : BaseEntity |
||||
|
{ |
||||
|
Task<TEntity> GetByIdAsync(int id); |
||||
|
Task<IEnumerable<TEntity>> GetAllAsync(); |
||||
|
Task<TEntity> AddAsync(TEntity entity); |
||||
|
Task UpdateAsync(TEntity entity); |
||||
|
Task DeleteAsync(int id); |
||||
|
|
||||
|
Task<PagedResult<TEntity>> GetPagedAsync(PagingParams pagingParams); |
||||
|
|
||||
|
|
||||
|
Task<PagedResult<TEntity>> GetPagedAsync( |
||||
|
Expression<Func<TEntity, bool>> filter = null, |
||||
|
PagingParams pagingParams = null); |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,234 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Expressions; |
||||
|
using System.Reflection; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using TaskManager.Entity; |
||||
|
using TaskManager.EntityFramework; |
||||
|
using Wood.Util; |
||||
|
|
||||
|
namespace TaskManager.EntityFramework.Repository |
||||
|
{ |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
public class Repository<TEntity> : IRepository<TEntity> |
||||
|
where TEntity : BaseEntity |
||||
|
{ |
||||
|
private readonly DbContext _context; |
||||
|
private readonly DbSet<TEntity> _dbSet; |
||||
|
|
||||
|
public Repository(DbContext context) |
||||
|
{ |
||||
|
_context = context; |
||||
|
_dbSet = context.Set<TEntity>(); |
||||
|
} |
||||
|
|
||||
|
public async Task<TEntity> GetByIdAsync(int id) |
||||
|
{ |
||||
|
return await _dbSet.FindAsync(id); |
||||
|
} |
||||
|
|
||||
|
public async Task<IEnumerable<TEntity>> GetAllAsync() |
||||
|
{ |
||||
|
return await _dbSet.ToListAsync(); |
||||
|
} |
||||
|
|
||||
|
public async Task<TEntity> AddAsync(TEntity entity) |
||||
|
{ |
||||
|
entity.CreationTime = DateTime.UtcNow; |
||||
|
await _dbSet.AddAsync(entity); |
||||
|
await _context.SaveChangesAsync(); |
||||
|
return entity; |
||||
|
} |
||||
|
|
||||
|
public async Task UpdateAsync(TEntity entity) |
||||
|
{ |
||||
|
|
||||
|
_dbSet.Update(entity); |
||||
|
await _context.SaveChangesAsync(); |
||||
|
} |
||||
|
|
||||
|
public async Task DeleteAsync(int id) |
||||
|
{ |
||||
|
var entity = await _dbSet.FindAsync(id); |
||||
|
if (entity != null) |
||||
|
{ |
||||
|
_dbSet.Remove(entity); |
||||
|
await _context.SaveChangesAsync(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task<PagedResult<TEntity>> GetPagedAsync(PagingParams pagingParams) |
||||
|
{ |
||||
|
return await _dbSet.AsNoTracking().ToPagedListAsync(pagingParams); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public async Task<PagedResult<TEntity>> GetPagedAsync( |
||||
|
Expression<Func<TEntity, bool>> filter = null, |
||||
|
PagingParams pagingParams = null) |
||||
|
{ |
||||
|
IQueryable<TEntity> query = _dbSet.AsNoTracking(); |
||||
|
|
||||
|
// 应用过滤条件
|
||||
|
if (filter != null) |
||||
|
{ |
||||
|
query = query.Where(filter); |
||||
|
} |
||||
|
|
||||
|
// 应用动态过滤
|
||||
|
if (pagingParams?.Filters != null && pagingParams.Filters.Any()) |
||||
|
{ |
||||
|
query = query.ApplyFilters(pagingParams.Filters); |
||||
|
} |
||||
|
|
||||
|
// 应用分页和排序
|
||||
|
pagingParams ??= new PagingParams(); |
||||
|
return await query.ToPagedListAsync(pagingParams); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
|
public class PagedResult<T> |
||||
|
{ |
||||
|
public List<T> Data { get; set; } |
||||
|
public int TotalCount { get; set; } |
||||
|
public int PageNumber { get; set; } |
||||
|
public int PageSize { get; set; } |
||||
|
public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize); |
||||
|
|
||||
|
public PagedResult() |
||||
|
{ |
||||
|
Data = new List<T>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
public class PagingParams |
||||
|
{ |
||||
|
private const int MaxPageSize = 50; |
||||
|
private int _pageSize = 10; |
||||
|
|
||||
|
public int PageNumber { get; set; } = 1; |
||||
|
public int PageSize |
||||
|
{ |
||||
|
get => _pageSize; |
||||
|
set => _pageSize = (value > MaxPageSize) ? MaxPageSize : value; |
||||
|
} |
||||
|
public string SortBy { get; set; } |
||||
|
public bool IsAscending { get; set; } = true; |
||||
|
|
||||
|
// 新增:过滤条件(键值对)
|
||||
|
public Dictionary<string, string> Filters { get; set; } = new(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
public static class QueryableExtensions |
||||
|
{ |
||||
|
public static IQueryable<T> ApplySort<T>(this IQueryable<T> query, string sortBy, bool isAscending) |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(sortBy)) return query; |
||||
|
|
||||
|
var parameter = Expression.Parameter(typeof(T), "x"); |
||||
|
var property = Expression.Property(parameter, sortBy); |
||||
|
var lambda = Expression.Lambda(property, parameter); |
||||
|
|
||||
|
var methodName = isAscending ? "OrderBy" : "OrderByDescending"; |
||||
|
var resultExpression = Expression.Call( |
||||
|
typeof(Queryable), |
||||
|
methodName, |
||||
|
new[] { typeof(T), property.Type }, |
||||
|
query.Expression, |
||||
|
Expression.Quote(lambda)); |
||||
|
|
||||
|
return query.Provider.CreateQuery<T>(resultExpression); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static IQueryable<T> ApplyFilters<T>(this IQueryable<T> query, Dictionary<string, string> filters) |
||||
|
{ |
||||
|
if (filters == null || !filters.Any()) return query; |
||||
|
|
||||
|
foreach (var filter in filters) |
||||
|
{ |
||||
|
var property = typeof(T).GetProperty(filter.Key, |
||||
|
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); |
||||
|
|
||||
|
if (property != null) |
||||
|
{ |
||||
|
var parameter = Expression.Parameter(typeof(T), "x"); |
||||
|
var propertyAccess = Expression.Property(parameter, property); |
||||
|
var constant = Expression.Constant( |
||||
|
Convert.ChangeType(filter.Value, property.PropertyType)); |
||||
|
|
||||
|
var equalExpression = Expression.Equal(propertyAccess, constant); |
||||
|
var lambda = Expression.Lambda<Func<T, bool>>(equalExpression, parameter); |
||||
|
|
||||
|
query = query.Where(lambda); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return query; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
public static IQueryable<T> ApplyStringFilter<T>(this IQueryable<T> query, |
||||
|
string propertyName, string value) |
||||
|
{ |
||||
|
var property = typeof(T).GetProperty(propertyName, |
||||
|
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); |
||||
|
|
||||
|
if (property != null && property.PropertyType == typeof(string) && !string.IsNullOrEmpty(value)) |
||||
|
{ |
||||
|
var parameter = Expression.Parameter(typeof(T), "x"); |
||||
|
var propertyAccess = Expression.Property(parameter, property); |
||||
|
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); |
||||
|
var constant = Expression.Constant(value); |
||||
|
|
||||
|
var containsExpression = Expression.Call(propertyAccess, containsMethod, constant); |
||||
|
var lambda = Expression.Lambda<Func<T, bool>>(containsExpression, parameter); |
||||
|
|
||||
|
query = query.Where(lambda); |
||||
|
} |
||||
|
|
||||
|
return query; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
public static async Task<PagedResult<T>> ToPagedListAsync<T>(this IQueryable<T> source, PagingParams pagingParams) |
||||
|
{ |
||||
|
var count = await source.CountAsync(); |
||||
|
var items = await source |
||||
|
.ApplySort(pagingParams.SortBy, pagingParams.IsAscending) |
||||
|
.Skip((pagingParams.PageNumber - 1) * pagingParams.PageSize) |
||||
|
.Take(pagingParams.PageSize) |
||||
|
.ToListAsync(); |
||||
|
|
||||
|
return new PagedResult<T> |
||||
|
{ |
||||
|
Data = items, |
||||
|
TotalCount = count, |
||||
|
PageNumber = pagingParams.PageNumber, |
||||
|
PageSize = pagingParams.PageSize |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using TaskManager.Entity; |
||||
|
using TaskManager.EntityFramework; |
||||
|
|
||||
|
namespace TaskManager.EntityFramework.Repository |
||||
|
{ |
||||
|
public interface ITaskUnitOfWork : IDisposable |
||||
|
{ |
||||
|
IRepository<TEntity> GetRepository<TEntity>() where TEntity : BaseEntity; |
||||
|
Task<int> SaveChangesAsync(); |
||||
|
} |
||||
|
|
||||
|
public class TaskUnitOfWork : ITaskUnitOfWork |
||||
|
{ |
||||
|
private readonly DbContext _context; |
||||
|
private readonly Dictionary<Type, object> _repositories = new(); |
||||
|
|
||||
|
public TaskUnitOfWork(DbContext context) |
||||
|
{ |
||||
|
_context = context; |
||||
|
} |
||||
|
|
||||
|
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : BaseEntity |
||||
|
{ |
||||
|
if (_repositories.TryGetValue(typeof(TEntity), out var repo)) |
||||
|
{ |
||||
|
return (IRepository<TEntity>)repo; |
||||
|
} |
||||
|
|
||||
|
var newRepo = new Repository<TEntity>(_context); |
||||
|
_repositories[typeof(TEntity)] = newRepo; |
||||
|
return newRepo; |
||||
|
} |
||||
|
|
||||
|
public async Task<int> SaveChangesAsync() |
||||
|
{ |
||||
|
return await _context.SaveChangesAsync(); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
_context.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,6 +1,6 @@ |
|||||
namespace TaskManager.Controllers |
namespace TaskManager.Controllers |
||||
{ |
{ |
||||
public class RecurringJobInputPageController |
//public class RecurringJobInputPageController<T,TINPUT>: RecurringJobBaseController
|
||||
{ |
//{
|
||||
} |
//}
|
||||
} |
} |
||||
|
@ -0,0 +1,75 @@ |
|||||
|
using Serilog; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Expressions; |
||||
|
using System.Security.Cryptography; |
||||
|
using System.Text; |
||||
|
using System.Text.RegularExpressions; |
||||
|
|
||||
|
namespace Wood.Util |
||||
|
{ |
||||
|
|
||||
|
public class PagedResult<T> |
||||
|
{ |
||||
|
public List<T> Items { get; set; } |
||||
|
public int TotalItems { get; set; } |
||||
|
public int PageNumber { get; set; } |
||||
|
public int PageSize { get; set; } |
||||
|
public int TotalPages => (int)Math.Ceiling(TotalItems / (double)PageSize); |
||||
|
public bool HasPreviousPage => PageNumber > 1; |
||||
|
public bool HasNextPage => PageNumber < TotalPages; |
||||
|
|
||||
|
public PagedResult() |
||||
|
{ |
||||
|
Items = new List<T>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static class QueryableExtensions |
||||
|
{ |
||||
|
public static PagedResult<T> ToPagedResult<T>(this IQueryable<T> query, int pageNumber, int pageSize) |
||||
|
{ |
||||
|
var result = new PagedResult<T> |
||||
|
{ |
||||
|
PageNumber = pageNumber, |
||||
|
PageSize = pageSize, |
||||
|
TotalItems = query.Count() |
||||
|
}; |
||||
|
|
||||
|
result.Items = query |
||||
|
.Skip((pageNumber - 1) * pageSize) |
||||
|
.Take(pageSize) |
||||
|
.ToList(); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static IQueryable<T> ApplySorting<T>(this IQueryable<T> query, string sortField, string sortDirection) |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(sortField)) |
||||
|
return query; |
||||
|
|
||||
|
var parameter = Expression.Parameter(typeof(T), "x"); |
||||
|
var property = Expression.Property(parameter, sortField); |
||||
|
var lambda = Expression.Lambda(property, parameter); |
||||
|
|
||||
|
string methodName = sortDirection?.ToLower() == "desc" ? "OrderByDescending" : "OrderBy"; |
||||
|
var resultExpression = Expression.Call( |
||||
|
typeof(Queryable), |
||||
|
methodName, |
||||
|
new[] { typeof(T), property.Type }, |
||||
|
query.Expression, |
||||
|
Expression.Quote(lambda)); |
||||
|
|
||||
|
return query.Provider.CreateQuery<T>(resultExpression); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
Loading…
Reference in new issue