439 lines
14 KiB
C#
439 lines
14 KiB
C#
|
|
|
|
using AutoMapper;
|
|
using IRaCIS.Core.Domain.Models;
|
|
using IRaCIS.Core.Infrastructure;
|
|
using IRaCIS.Core.Infrastructure.Extention;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Threading.Tasks;
|
|
using EFCore.BulkExtensions;
|
|
using IRaCIS.Core.Domain.Share;
|
|
|
|
namespace IRaCIS.Core.Infra.EFCore
|
|
{
|
|
public interface IRepository<TEntity> : ICommandRepository<TEntity>, IQueryRepository<TEntity> where TEntity : Entity
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#region 泛型通用版本
|
|
|
|
|
|
public interface IRepository
|
|
{
|
|
IQueryable<T> GetQueryable<T>(bool isTraking = false) where T : Entity;
|
|
DbSet<T> Set<T>() where T : Entity;
|
|
|
|
IQueryable<T> WhereIf<T>(bool condition, Expression<Func<T, bool>> filter) where T : Entity;
|
|
|
|
Task<T> InsertOrUpdateAsync<T, TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<T>[] verify) where T : Entity;
|
|
|
|
EntityEntry<T> Entry<T>(T t) where T : Entity;
|
|
|
|
//Task<T> InsertOrUpdateAsync<T, TFrom>(this DbSet<T> dbset, TFrom from, bool autoSave = false, params EntityVerifyExp<T>[] verify) where T : Entity;
|
|
|
|
Task<bool> AnyAsync<T>(Expression<Func<T, bool>> filter, bool ignoreQueryFilters = false) where T : Entity;
|
|
|
|
Task<T> FirstOrDefaultAsync<T>(Expression<Func<T, bool>> exp = null, bool ignoreQueryFilters = false) where T : Entity;
|
|
Task<int> CountAsync<T>(Expression<Func<T, bool>> exp = null, bool ignoreQueryFilters = false) where T : Entity;
|
|
|
|
IQueryable<T> Where<T>(Expression<Func<T, bool>> exp = null, bool isTraking = false, bool ignoreQueryFilters = false) where T : Entity;
|
|
|
|
ValueTask<T> FindAsync<T>(Guid id) where T : Entity;
|
|
|
|
ValueTask<T> AddAsync<T>(T entity, bool autoSave = false) where T : Entity;
|
|
|
|
Task UpdateRange<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity;
|
|
Task<bool> AddRangeAsync<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity;
|
|
|
|
Task<bool> UpdateAsync<T>(T entity, bool autoSave = false) where T : Entity;
|
|
|
|
Task<bool> DeleteAsync<T>(T entity, bool autoSave = false) where T : Entity;
|
|
|
|
Task<bool> DeleteManyAsync<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity;
|
|
|
|
Task<bool> SaveChangesAsync();
|
|
|
|
Task<bool> BatchDeleteAsync<T>(Expression<Func<T, bool>> deleteFilter) where T : Entity;
|
|
|
|
Task<bool> BatchUpdateAsync<T>(Expression<Func<T, bool>> where, Expression<Func<T, T>> updateFactory) where T : Entity;
|
|
}
|
|
|
|
public class Repository : IRepository
|
|
{
|
|
private IRaCISDBContext _dbContext { get; }
|
|
|
|
public IMapper _mapper { get; set; }
|
|
|
|
public IUserInfo _userInfo { get; set; }
|
|
|
|
public Repository(IRaCISDBContext dbContext, IMapper mapper, IUserInfo userInfo)
|
|
{
|
|
_dbContext = dbContext;
|
|
_mapper = mapper;
|
|
_userInfo = userInfo;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置是使用哪个仓储 默认不跟踪
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="isTraking"></param>
|
|
/// <returns></returns>
|
|
|
|
public IQueryable<T> GetQueryable<T>(bool isTraking = false) where T : Entity
|
|
{
|
|
IQueryable<T> query = _dbContext.Set<T>();
|
|
|
|
if (!isTraking)
|
|
{
|
|
query = query.AsNoTracking();
|
|
}
|
|
return query;
|
|
}
|
|
public DbSet<T> Set<T>() where T : Entity
|
|
{
|
|
return _dbContext.Set<T>();
|
|
}
|
|
|
|
public IQueryable<T> WhereIf<T>(bool condition, Expression<Func<T, bool>> filter) where T : Entity
|
|
{
|
|
IQueryable<T> query = _dbContext.Set<T>().AsNoTracking();
|
|
return condition ? query.Where(filter) : query;
|
|
}
|
|
|
|
|
|
|
|
public async Task<T> InsertOrUpdateAsync<T, TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<T>[] verify) where T : Entity
|
|
{
|
|
|
|
var entity = _mapper.Map<T>(from);
|
|
|
|
if (entity.Id == Guid.Empty)
|
|
{
|
|
// verifyExp
|
|
|
|
//await verify.Where(t => t.verifyType != VerifyEnum.OnlyUpdate && t.IsVerify).ToList().ForeachAsync(async verifyItem =>
|
|
//{
|
|
// if (await _dbContext.Set<T>().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
|
|
// {
|
|
// throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
// }
|
|
//});
|
|
|
|
foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyUpdate && t.IsVerify))
|
|
{
|
|
if (await _dbContext.Set<T>().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
|
|
{
|
|
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
}
|
|
}
|
|
|
|
await _dbContext.Set<T>().AddAsync(entity).ConfigureAwait(false);
|
|
|
|
if (autoSave)
|
|
{
|
|
await SaveChangesAsync();
|
|
|
|
}
|
|
return entity;
|
|
|
|
}
|
|
else
|
|
{
|
|
// verifyExp
|
|
|
|
//await verify.Where(t => t.verifyType != VerifyEnum.OnlyAdd && t.IsVerify).ToList().ForeachAsync(async verifyItem =>
|
|
// {
|
|
// if (verifyItem.verifyType == VerifyEnum.OnlyUpdate)
|
|
// {
|
|
// if (await _dbContext.Set<T>().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
|
|
// {
|
|
// throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
// }
|
|
// }
|
|
// else if (verifyItem.verifyType == VerifyEnum.Both)
|
|
// {
|
|
// if (await _dbContext.Set<T>().AnyAsync(verifyItem.VerifyExp.And(t => t.Id != entity.Id)).ConfigureAwait(false))
|
|
// {
|
|
// throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
// }
|
|
// }
|
|
|
|
// });
|
|
|
|
foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyAdd && t.IsVerify))
|
|
{
|
|
if (verifyItem.verifyType == VerifyEnum.OnlyUpdate)
|
|
{
|
|
if (await _dbContext.Set<T>().IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
|
|
{
|
|
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
}
|
|
}
|
|
else if (verifyItem.verifyType == VerifyEnum.Both)
|
|
{
|
|
if (await _dbContext.Set<T>().IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp.And(t => t.Id != entity.Id)).ConfigureAwait(false))
|
|
{
|
|
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
var dbEntity = await FirstOrDefaultAsync<T>(t => t.Id == entity.Id).ConfigureAwait(false);
|
|
|
|
var dbBeforEntity = dbEntity.Clone();
|
|
|
|
_mapper.Map(from, dbEntity);
|
|
|
|
if (autoSave)
|
|
{
|
|
await SaveChangesAsync();
|
|
}
|
|
return dbBeforEntity;
|
|
|
|
}
|
|
}
|
|
|
|
public EntityEntry<T> Entry<T>(T t) where T : Entity
|
|
{
|
|
return _dbContext.Entry<T>(t);
|
|
}
|
|
public async Task<bool> AnyAsync<T>(Expression<Func<T, bool>> filter, bool ignoreQueryFilters = false) where T : Entity
|
|
{
|
|
|
|
var query = _dbContext.Set<T>().AsQueryable();
|
|
|
|
if (ignoreQueryFilters)
|
|
{
|
|
query = query.IgnoreQueryFilters();
|
|
}
|
|
|
|
return await query.AsNoTracking().AnyAsync(filter).ConfigureAwait(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 基本查询 异步
|
|
|
|
/// <summary>
|
|
/// 跟踪查询某个实体 --异步 默认是跟踪查询
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="exp"></param>
|
|
/// <returns></returns>
|
|
///
|
|
public async Task<int> CountAsync<T>(Expression<Func<T, bool>> exp = null, bool ignoreQueryFilters = false) where T : Entity
|
|
{
|
|
var query = _dbContext.Set<T>().AsQueryable();
|
|
|
|
if (ignoreQueryFilters)
|
|
{
|
|
query = query.IgnoreQueryFilters();
|
|
}
|
|
|
|
if (exp != null)
|
|
{
|
|
query = query.Where(exp);
|
|
}
|
|
|
|
return await query.CountAsync().ConfigureAwait(false);
|
|
|
|
|
|
}
|
|
public async Task<T> FirstOrDefaultAsync<T>(Expression<Func<T, bool>> exp = null, bool ignoreQueryFilters = false) where T : Entity
|
|
{
|
|
|
|
var query = _dbContext.Set<T>().AsQueryable();
|
|
|
|
if (ignoreQueryFilters)
|
|
{
|
|
query = query.IgnoreQueryFilters();
|
|
}
|
|
|
|
if (exp != null)
|
|
{
|
|
query = query.Where(exp);
|
|
}
|
|
|
|
return await query.FirstOrDefaultAsync().ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 过滤 默认不跟踪
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="exp"></param>
|
|
/// <param name="isTraking"></param>
|
|
/// <returns></returns>
|
|
public IQueryable<T> Where<T>(Expression<Func<T, bool>> exp = null, bool isTraking = false, bool ignoreQueryFilters = false) where T : Entity
|
|
{
|
|
IQueryable<T> query = _dbContext.Set<T>();
|
|
|
|
if (ignoreQueryFilters)
|
|
{
|
|
query = query.IgnoreQueryFilters();
|
|
}
|
|
|
|
if (!isTraking)
|
|
{
|
|
query = query.AsNoTracking();
|
|
}
|
|
|
|
if (exp != null)
|
|
{
|
|
query = query.Where(exp);
|
|
}
|
|
return query;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 首先在内存中查找,其次再找数据库
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
public async ValueTask<T> FindAsync<T>(Guid id) where T : Entity
|
|
{
|
|
return await _dbContext.Set<T>().FindAsync(id).ConfigureAwait(false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 基本添加、更新、删除 异步
|
|
|
|
public async ValueTask<T> AddAsync<T>(T entity, bool autoSave = false) where T : Entity
|
|
{
|
|
|
|
await _dbContext.Set<T>().AddAsync(entity).ConfigureAwait(false);
|
|
|
|
if (autoSave)
|
|
{
|
|
await SaveChangesAsync();
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
public async Task<bool> AddRangeAsync<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity
|
|
{
|
|
await _dbContext.Set<T>().AddRangeAsync(entities).ConfigureAwait(false);
|
|
|
|
if (autoSave)
|
|
{
|
|
return await SaveChangesAsync();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task UpdateRange<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity
|
|
{
|
|
_dbContext.Set<T>().UpdateRange(entities);
|
|
|
|
if (autoSave)
|
|
{
|
|
await SaveChangesAsync();
|
|
}
|
|
|
|
}
|
|
|
|
public async Task<bool> UpdateAsync<T>(T entity, bool autoSave = false) where T : Entity
|
|
{
|
|
_dbContext.Set<T>().Update(entity);
|
|
|
|
if (autoSave)
|
|
{
|
|
return await SaveChangesAsync();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
public async Task<bool> DeleteAsync<T>(T entity, bool autoSave = false) where T : Entity
|
|
{
|
|
_dbContext.Set<T>().Remove(entity);
|
|
|
|
if (autoSave)
|
|
{
|
|
return await SaveChangesAsync();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task<bool> DeleteManyAsync<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity
|
|
{
|
|
_dbContext.Set<T>().RemoveRange(entities);
|
|
|
|
if (autoSave)
|
|
{
|
|
return await SaveChangesAsync();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task<bool> SaveChangesAsync()
|
|
{
|
|
|
|
return await _dbContext.SaveChangesAsync().ConfigureAwait(false) > 0;
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
public async Task<bool> BatchDeleteAsync<T>(Expression<Func<T, bool>> deleteFilter) where T : Entity
|
|
{
|
|
if (deleteFilter == null) throw new ArgumentNullException(nameof(deleteFilter));
|
|
|
|
return await _dbContext.Set<T>().AsNoTracking().Where(deleteFilter).BatchDeleteAsync().ConfigureAwait(false) > 0;
|
|
}
|
|
|
|
public async Task<bool> BatchUpdateAsync<T>(Expression<Func<T, bool>> whereFilter, Expression<Func<T, T>> updateFactory) where T : Entity
|
|
{
|
|
if (whereFilter == null) throw new ArgumentNullException(nameof(whereFilter));
|
|
|
|
var bindings = ((MemberInitExpression)updateFactory.Body).Bindings.ToList();
|
|
|
|
if (typeof(IAuditUpdate).IsAssignableFrom(typeof(T)))
|
|
{
|
|
|
|
bindings.Add(Expression.Bind(typeof(T).GetMember(nameof(IAuditUpdate.UpdateTime))[0], Expression.Constant(DateTime.Now)));
|
|
bindings.Add(Expression.Bind(typeof(TR).GetMember(nameof(IAuditUpdate.UpdateUserId))[0], Expression.Constant(_userInfo.Id)));
|
|
}
|
|
|
|
|
|
var member = Expression.MemberInit(Expression.New(typeof(T)), bindings);
|
|
|
|
var factory = Expression.Lambda<Func<T, T>>(member, Expression.Parameter(typeof(T), "x"));
|
|
|
|
return await _dbContext.Set<T>().AsNoTracking().IgnoreQueryFilters().Where(whereFilter).BatchUpdateAsync(updateFactory).ConfigureAwait(false) > 0;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
}
|