整理仓储
parent
d1ce475e9c
commit
5ee3fc5b79
|
@ -1,30 +0,0 @@
|
||||||
namespace IRaCIS.Core.Domain.Share
|
|
||||||
{
|
|
||||||
public enum DoctorTrialState
|
|
||||||
{
|
|
||||||
NotApply = 0,
|
|
||||||
|
|
||||||
//已申请
|
|
||||||
HasAppliedDownLoad = 1,
|
|
||||||
|
|
||||||
//审核通过
|
|
||||||
AuditPass = 2,
|
|
||||||
|
|
||||||
AuditFailed = 3,
|
|
||||||
|
|
||||||
//已下载
|
|
||||||
ResumeHasDownLoad = 4,
|
|
||||||
|
|
||||||
//已邀请--已确认该名单
|
|
||||||
Inviting = 5,
|
|
||||||
|
|
||||||
//同意入组
|
|
||||||
InviteConfirmed = 6,
|
|
||||||
|
|
||||||
//拒绝入组
|
|
||||||
InviteRefused = 7,
|
|
||||||
|
|
||||||
HasUploadAgreement = 8
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using System;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Infra.EFCore
|
|
||||||
{
|
|
||||||
public class EntityVerifyExp<TEntity> where TEntity : Entity
|
|
||||||
{
|
|
||||||
//验证表达式树
|
|
||||||
public Expression<Func<TEntity, bool>> VerifyExp { get; set; }
|
|
||||||
|
|
||||||
//验证提示错误信息
|
|
||||||
public string VerifyMsg { get; set; }
|
|
||||||
|
|
||||||
public VerifyEnum verifyType { get; set; } = VerifyEnum.Both;
|
|
||||||
|
|
||||||
public bool IsVerify { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum VerifyEnum
|
|
||||||
{
|
|
||||||
OnlyAdd = 1,
|
|
||||||
|
|
||||||
OnlyUpdate = 2,
|
|
||||||
|
|
||||||
Both = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
Task<bool> UpdateAsync(TEntity entity, Expression<Func<TEntity, TEntity>> updateFactory,
|
Task<bool> UpdateAsync(TEntity entity, Expression<Func<TEntity, TEntity>> updateFactory,
|
||||||
bool autoSave = false, CancellationToken cancellationToken = default);
|
bool autoSave = false, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary> EF跟踪方式 先查询出来,再更新部分字段 </summary>
|
/// <summary> EF跟踪方式 会去数据库查询完整的实体,再更新部分字段 </summary>
|
||||||
Task<TEntity> UpdatePartialFromQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
|
Task<TEntity> UpdatePartialFromQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
|
||||||
bool autoSave = false, bool ignoreQueryFilter = false, CancellationToken cancellationToken = default);
|
bool autoSave = false, bool ignoreQueryFilter = false, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
/// <param name="exp"></param>
|
/// <param name="exp"></param>
|
||||||
/// <param name="ignoreQueryFilters"></param>
|
/// <param name="ignoreQueryFilters"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> exp = null, bool isTracking = false);
|
Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> exp = null, bool isTracking = false,bool ignoreQueryFilters = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///跟踪 查询单个实体,会出现NUll
|
///跟踪 查询单个实体,会出现NUll
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
using EFCore.BulkExtensions;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
{
|
||||||
|
public class EntityVerifyExp<TEntity> where TEntity : Entity
|
||||||
|
{
|
||||||
|
//验证表达式树
|
||||||
|
public Expression<Func<TEntity, bool>> VerifyExp { get; set; }
|
||||||
|
|
||||||
|
//验证提示错误信息
|
||||||
|
public string VerifyMsg { get; set; }
|
||||||
|
|
||||||
|
public VerifyEnum verifyType { get; set; } = VerifyEnum.Both;
|
||||||
|
|
||||||
|
public bool IsVerify { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum VerifyEnum
|
||||||
|
{
|
||||||
|
OnlyAdd = 1,
|
||||||
|
|
||||||
|
OnlyUpdate = 2,
|
||||||
|
|
||||||
|
Both = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class EntityAction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///添加和更新的时候,通常需要与数据库已存在的数据进行校验,添加更新的区分在于是否需要排除自己
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="_dbContext"></param>
|
||||||
|
/// <param name="isAdd"></param>
|
||||||
|
/// <param name="verify"></param>
|
||||||
|
/// <param name="entitydId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||||
|
public static async Task EntityVerifyAsync<T>(this IRaCISDBContext _dbContext, bool isAdd, EntityVerifyExp<T>[] verify, Guid? entitydId = null) where T : Entity
|
||||||
|
{
|
||||||
|
|
||||||
|
if (isAdd)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyAdd && t.IsVerify))
|
||||||
|
{
|
||||||
|
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 != entitydId)).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///注意 模型标注了 ConcurrencyCheck的属性,这样的实体,不适合用部分字段更新,ef生成的更新sql会自动带上ConcurrencyCheck的属性条件
|
||||||
|
/// <summary>EntityState.Detached的实体 修改 部分字段</summary>
|
||||||
|
public static void EntityModifyPartialFiled<T>(this IRaCISDBContext _dbContext,T waitModifyEntity, Expression<Func<T, T>> updateFactory) where T : Entity
|
||||||
|
{
|
||||||
|
var entityEntry = _dbContext.Entry(waitModifyEntity);
|
||||||
|
entityEntry.State = EntityState.Detached;
|
||||||
|
|
||||||
|
var list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name)
|
||||||
|
.Select(propName => typeof(T).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList();
|
||||||
|
|
||||||
|
Func<T, T> func = updateFactory.Compile();
|
||||||
|
|
||||||
|
T applyObj = func(waitModifyEntity);
|
||||||
|
|
||||||
|
//深拷贝更新之前实体信息
|
||||||
|
//var copyObj = waitModifyEntity.Clone();
|
||||||
|
|
||||||
|
foreach (PropertyInfo prop in list)
|
||||||
|
{
|
||||||
|
object value = prop.GetValue(applyObj);
|
||||||
|
prop.SetValue(waitModifyEntity, value);
|
||||||
|
|
||||||
|
_dbContext.Entry(waitModifyEntity).Property(prop.Name).IsModified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region 不走EF 跟踪机制的删除 更新 以及批量操作
|
||||||
|
|
||||||
|
/// <summary>批量删除,相当于原生sql, 没用EF跟踪方式(所有查询出来,再删除 浪费性能)</summary>
|
||||||
|
public static async Task<bool> BatchDeleteNoTrackingAsync<T>(this IRaCISDBContext _dbContext,Expression<Func<T, bool>> deleteFilter) where T : Entity
|
||||||
|
{
|
||||||
|
if (deleteFilter == null) throw new ArgumentNullException(nameof(deleteFilter));
|
||||||
|
|
||||||
|
return await _dbContext.Set<T>().IgnoreQueryFilters().Where(deleteFilter).BatchDeleteAsync() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>批量更新,相当于原生sql, 没用EF跟踪方式(所有查询出来,再更新 浪费性能)</summary>
|
||||||
|
public static async Task<bool> BatchUpdateNoTrackingAsync<T>(this IRaCISDBContext _dbContext,Expression<Func<T, bool>> where, Expression<Func<T, T>> updateFactory,Guid updateUserId) where T : Entity
|
||||||
|
{
|
||||||
|
if (where == null) throw new ArgumentNullException(nameof(where));
|
||||||
|
|
||||||
|
var bindings = ((MemberInitExpression)updateFactory.Body).Bindings.ToList();
|
||||||
|
|
||||||
|
var hasPropNameList = bindings.Select(t => t.Member.Name).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof(IAuditUpdate).IsAssignableFrom(typeof(T)))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateTime)))
|
||||||
|
{
|
||||||
|
bindings.Add(Expression.Bind(typeof(T).GetMember(nameof(IAuditUpdate.UpdateTime))[0], Expression.Constant(DateTime.Now)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateUserId)))
|
||||||
|
{
|
||||||
|
bindings.Add(Expression.Bind(typeof(T).GetMember(nameof(IAuditUpdate.UpdateUserId))[0], Expression.Constant(updateUserId)));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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>().IgnoreQueryFilters().Where(where).BatchUpdateAsync(factory).ConfigureAwait(false) > 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
public interface IRepository
|
public interface IRepository
|
||||||
{
|
{
|
||||||
IQueryable<T> GetQueryable<T>(bool isTraking = false) where T : Entity;
|
IQueryable<T> GetQueryable<T>(bool ignoreQueryFilters = false) where T : Entity;
|
||||||
DbSet<T> Set<T>() where T : Entity;
|
DbSet<T> Set<T>() where T : Entity;
|
||||||
EntityEntry<T> Entry<T>(T t) where T : Entity;
|
EntityEntry<T> Entry<T>(T t) where T : Entity;
|
||||||
|
|
||||||
|
@ -92,15 +92,15 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
/// <param name="isTraking"></param>
|
/// <param name="isTraking"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
|
||||||
public IQueryable<T> GetQueryable<T>(bool isTraking = false) where T : Entity
|
public IQueryable<T> GetQueryable<T>(bool ignoreQueryFilters = false) where T : Entity
|
||||||
{
|
{
|
||||||
IQueryable<T> query = _dbContext.Set<T>();
|
IQueryable<T> query = _dbContext.Set<T>();
|
||||||
|
|
||||||
if (!isTraking)
|
if (ignoreQueryFilters)
|
||||||
{
|
{
|
||||||
query = query.AsNoTracking();
|
query = query.IgnoreQueryFilters();
|
||||||
}
|
}
|
||||||
return query;
|
return query.AsNoTracking();
|
||||||
}
|
}
|
||||||
public DbSet<T> Set<T>() where T : Entity
|
public DbSet<T> Set<T>() where T : Entity
|
||||||
{
|
{
|
||||||
|
@ -141,49 +141,13 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private async Task EntityVerifyAsync<T>(bool isAdd, EntityVerifyExp<T>[] verify, Guid? entitydId = null) where T : Entity
|
|
||||||
{
|
|
||||||
|
|
||||||
if (isAdd)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyAdd && t.IsVerify))
|
|
||||||
{
|
|
||||||
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 != entitydId)).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<T> InsertFromDTOAsync<T, TFrom>(TFrom from, bool autoSave = false,
|
public async Task<T> InsertFromDTOAsync<T, TFrom>(TFrom from, bool autoSave = false,
|
||||||
params EntityVerifyExp<T>[] verify) where T : Entity
|
params EntityVerifyExp<T>[] verify) where T : Entity
|
||||||
{
|
{
|
||||||
|
|
||||||
var entity = _mapper.Map<T>(from);
|
var entity = _mapper.Map<T>(from);
|
||||||
|
|
||||||
await EntityVerifyAsync(true, verify);
|
await _dbContext.EntityVerifyAsync(true, verify);
|
||||||
|
|
||||||
entity = await AddAsync(entity, autoSave);
|
entity = await AddAsync(entity, autoSave);
|
||||||
|
|
||||||
|
@ -195,7 +159,8 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
{
|
{
|
||||||
var entity = _mapper.Map<T>(from);
|
var entity = _mapper.Map<T>(from);
|
||||||
|
|
||||||
await EntityVerifyAsync(false, verify, entity.Id);
|
|
||||||
|
await _dbContext.EntityVerifyAsync(false, verify, entity.Id);
|
||||||
|
|
||||||
var dbEntity = await _dbContext.Set<T>().IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == entity.Id).ConfigureAwait(false);
|
var dbEntity = await _dbContext.Set<T>().IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == entity.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -359,10 +324,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
await _dbContext.Set<T>().AddAsync(entity).ConfigureAwait(false);
|
await _dbContext.Set<T>().AddAsync(entity).ConfigureAwait(false);
|
||||||
|
|
||||||
if (autoSave)
|
await SaveChangesAsync(autoSave);
|
||||||
{
|
|
||||||
await SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
@ -412,41 +374,14 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
public async Task<bool> BatchDeleteAsync<T>(Expression<Func<T, bool>> deleteFilter) where T : Entity
|
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.BatchDeleteNoTrackingAsync(deleteFilter);
|
||||||
|
|
||||||
return await _dbContext.Set<T>().AsNoTracking().IgnoreQueryFilters().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
|
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();
|
return await _dbContext.BatchUpdateNoTrackingAsync(whereFilter, updateFactory, _userInfo.Id);
|
||||||
|
|
||||||
if (typeof(IAuditUpdate).IsAssignableFrom(typeof(T)))
|
|
||||||
{
|
|
||||||
|
|
||||||
var hasPropNameList = bindings.Select(t => t.Member.Name).ToList();
|
|
||||||
|
|
||||||
if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateTime)))
|
|
||||||
{
|
|
||||||
bindings.Add(Expression.Bind(typeof(T).GetMember(nameof(IAuditUpdate.UpdateTime))[0], Expression.Constant(DateTime.Now)));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateUserId)))
|
|
||||||
{
|
|
||||||
bindings.Add(Expression.Bind(typeof(T).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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -464,46 +399,22 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
foreach (var needUpdateEntity in searchEntityList)
|
foreach (var needUpdateEntity in searchEntityList)
|
||||||
{
|
{
|
||||||
await UpdateAsync(needUpdateEntity, updateFactory, autoSave);
|
_dbContext.EntityModifyPartialFiled(needUpdateEntity, updateFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await SaveChangesAsync(autoSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> UpdateAsync<T>(T waitModifyEntity, Expression<Func<T, T>> updateFactory, bool autoSave = false) where T : Entity
|
public async Task<bool> UpdateAsync<T>(T waitModifyEntity, Expression<Func<T, T>> updateFactory, bool autoSave = false) where T : Entity
|
||||||
{
|
{
|
||||||
var entityEntry = _dbContext.Entry(waitModifyEntity);
|
|
||||||
entityEntry.State = EntityState.Detached;
|
|
||||||
|
|
||||||
|
_dbContext.EntityModifyPartialFiled(waitModifyEntity, updateFactory);
|
||||||
ModifyPartialFiled(waitModifyEntity, updateFactory);
|
|
||||||
|
|
||||||
return await SaveChangesAsync(autoSave);
|
return await SaveChangesAsync(autoSave);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>更新后拥有完整的实体信息,便于稽查</summary>
|
|
||||||
private void ModifyPartialFiled<T>(T waitModifyEntity, Expression<Func<T, T>> updateFactory)
|
|
||||||
{
|
|
||||||
List<PropertyInfo> list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name)
|
|
||||||
.Select(propName => typeof(T).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList();
|
|
||||||
|
|
||||||
Func<T, T> func = updateFactory.Compile();
|
|
||||||
|
|
||||||
T applyObj = func(waitModifyEntity);
|
|
||||||
|
|
||||||
//深拷贝更新之前实体信息
|
|
||||||
//var copyObj = waitModifyEntity.Clone();
|
|
||||||
|
|
||||||
foreach (PropertyInfo prop in list)
|
|
||||||
{
|
|
||||||
object value = prop.GetValue(applyObj);
|
|
||||||
prop.SetValue(waitModifyEntity, value);
|
|
||||||
|
|
||||||
_dbContext.Entry(waitModifyEntity).Property(prop.Name).IsModified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -43,6 +43,8 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 异步 EF 跟踪 添加
|
#region 异步 EF 跟踪 添加
|
||||||
public async Task<IEnumerable<TEntity>> AddRangeAsync(IEnumerable<TEntity> entities, bool autoSave = false)
|
public async Task<IEnumerable<TEntity>> AddRangeAsync(IEnumerable<TEntity> entities, bool autoSave = false)
|
||||||
{
|
{
|
||||||
|
@ -70,7 +72,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
public async Task<TEntity> InsertFromDTOAsync<TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
|
public async Task<TEntity> InsertFromDTOAsync<TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
|
||||||
{
|
{
|
||||||
|
|
||||||
await EntityVerifyAsync(true, verify);
|
await _dbContext.EntityVerifyAsync(true, verify);
|
||||||
|
|
||||||
var entity = _mapper.Map<TEntity>(from);
|
var entity = _mapper.Map<TEntity>(from);
|
||||||
|
|
||||||
|
@ -93,7 +95,9 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
var entity = _mapper.Map<TEntity>(from);
|
var entity = _mapper.Map<TEntity>(from);
|
||||||
|
|
||||||
await EntityVerifyAsync(false, verify, entity.Id);
|
//await EntityVerifyAsync(false, verify, entity.Id);
|
||||||
|
|
||||||
|
await _dbContext.EntityVerifyAsync(false, verify, entity.Id);
|
||||||
|
|
||||||
var dbEntity = await _dbSet.IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == entity.Id).ConfigureAwait(false);
|
var dbEntity = await _dbSet.IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == entity.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -131,12 +135,18 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary> EF跟踪方式 生成 部分字段更新, 通过主键id 和表达式树 更新部分字段
|
/// <summary> EF跟踪方式 生成 部分字段更新, 跟踪的实体仅有修改的属性的值有具体意义,没有从数据库查询完整的实体</summary>
|
||||||
/// 例如 Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584"),u => new Dictionary() { ParentId = null, Code = "test" }默认会去处理更新更新人 更新时间</summary>
|
|
||||||
|
|
||||||
public async Task UpdatePartialNoQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
|
public async Task UpdatePartialNoQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
|
||||||
{
|
{
|
||||||
await SetPartialFieldUpdateAsync(id, updateFactory, verify);
|
|
||||||
|
await _dbContext.EntityVerifyAsync(false, verify, id);
|
||||||
|
|
||||||
|
var entity = new TEntity() { Id = id };
|
||||||
|
|
||||||
|
_dbContext.EntityModifyPartialFiled(entity, updateFactory);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await SaveChangesAsync(autoSave);
|
await SaveChangesAsync(autoSave);
|
||||||
|
|
||||||
|
@ -147,52 +157,16 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
public async Task<bool> UpdatePartialNowNoQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
|
public async Task<bool> UpdatePartialNowNoQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
|
||||||
params EntityVerifyExp<TEntity>[] verify)
|
params EntityVerifyExp<TEntity>[] verify)
|
||||||
{
|
{
|
||||||
await SetPartialFieldUpdateAsync(id, updateFactory, verify);
|
await _dbContext.EntityVerifyAsync(false, verify, id);
|
||||||
|
|
||||||
|
var entity = new TEntity() { Id = id };
|
||||||
|
|
||||||
|
_dbContext.EntityModifyPartialFiled(entity, updateFactory);
|
||||||
|
|
||||||
return await SaveChangesAsync(true);
|
return await SaveChangesAsync(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>注意 模型标注了 ConcurrencyCheck的属性,这样的实体,不适合用部分字段更新,ef生成的更新sql会自动带上ConcurrencyCheck的属性条件</summary>
|
|
||||||
private async Task SetPartialFieldUpdateAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, params EntityVerifyExp<TEntity>[] verify)
|
|
||||||
{
|
|
||||||
await EntityVerifyAsync(false, verify, id);
|
|
||||||
|
|
||||||
var entity = new TEntity() { Id = id };
|
|
||||||
|
|
||||||
var entityEntry = _dbContext.Entry(entity);
|
|
||||||
|
|
||||||
entityEntry.State = EntityState.Detached;
|
|
||||||
|
|
||||||
|
|
||||||
List<PropertyInfo> list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name)
|
|
||||||
.Select(propName => typeof(TEntity).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList();
|
|
||||||
|
|
||||||
Func<TEntity, TEntity> func = updateFactory.Compile();
|
|
||||||
|
|
||||||
TEntity applyObj = func(entity);
|
|
||||||
|
|
||||||
foreach (PropertyInfo prop in list)
|
|
||||||
{
|
|
||||||
object value = prop.GetValue((object)applyObj);
|
|
||||||
prop.SetValue((object)entity, value);
|
|
||||||
|
|
||||||
_dbContext.Entry(entity).Property(prop.Name).IsModified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Test
|
|
||||||
|
|
||||||
|
|
||||||
//updateFactory.Compile()(entity);
|
|
||||||
|
|
||||||
//List<string> propNameList = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name).ToList();
|
|
||||||
|
|
||||||
//foreach (string propName in propNameList)
|
|
||||||
//{
|
|
||||||
// _dbContext.Entry(entity).Property(propName).IsModified = true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -206,25 +180,15 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
{
|
{
|
||||||
_dbSet.Update(entity);
|
_dbSet.Update(entity);
|
||||||
|
|
||||||
if (autoSave)
|
return await SaveChangesAsync(autoSave);
|
||||||
{
|
|
||||||
return await SaveChangesAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>EF跟踪方式 外层先有查询好的完成实体,再更新部分字段 稽查的时候需要完整的实体信息</summary>
|
/// <summary>EF跟踪方式 外层先有查询好的完成实体,再更新部分字段 稽查的时候需要完整的实体信息</summary>
|
||||||
public async Task<bool> UpdateAsync(TEntity waitModifyEntity, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, CancellationToken cancellationToken = default)
|
public async Task<bool> UpdateAsync(TEntity waitModifyEntity, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var entityEntry = _dbContext.Entry(waitModifyEntity);
|
|
||||||
entityEntry.State = EntityState.Detached;
|
|
||||||
|
|
||||||
|
_dbContext.EntityModifyPartialFiled(waitModifyEntity, updateFactory);
|
||||||
ModifyPartialFiled(waitModifyEntity, updateFactory);
|
|
||||||
|
|
||||||
return await SaveChangesAsync(autoSave);
|
return await SaveChangesAsync(autoSave);
|
||||||
|
|
||||||
|
@ -238,7 +202,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
var query = ignoreQueryFilter ? _dbSet.AsNoTracking().IgnoreQueryFilters() : _dbSet.AsNoTracking();
|
var query = ignoreQueryFilter ? _dbSet.AsNoTracking().IgnoreQueryFilters() : _dbSet.AsNoTracking();
|
||||||
//不跟踪 查询出来的实体就是Detached
|
//不跟踪 查询出来的实体就是Detached
|
||||||
var searchEntity = await query.IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == id);
|
var searchEntity = await query.FirstOrDefaultAsync(t => t.Id == id);
|
||||||
|
|
||||||
if (searchEntity == null)
|
if (searchEntity == null)
|
||||||
{
|
{
|
||||||
|
@ -246,9 +210,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
" Update object not exist in db,Please check if the parameter Id is passed incorrectly");
|
" Update object not exist in db,Please check if the parameter Id is passed incorrectly");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_dbContext.EntityModifyPartialFiled(searchEntity, updateFactory);
|
||||||
ModifyPartialFiled(searchEntity, updateFactory);
|
|
||||||
|
|
||||||
|
|
||||||
await SaveChangesAsync(autoSave);
|
await SaveChangesAsync(autoSave);
|
||||||
|
|
||||||
|
@ -269,35 +231,14 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
|
|
||||||
foreach (var needUpdateEntity in searchEntityList)
|
foreach (var needUpdateEntity in searchEntityList)
|
||||||
{
|
{
|
||||||
await UpdateAsync(needUpdateEntity, updateFactory, autoSave);
|
await UpdateAsync(needUpdateEntity, updateFactory, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await SaveChangesAsync(autoSave);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>更新后拥有完整的实体信息,便于稽查</summary>
|
|
||||||
private void ModifyPartialFiled(TEntity waitModifyEntity, Expression<Func<TEntity, TEntity>> updateFactory)
|
|
||||||
{
|
|
||||||
List<PropertyInfo> list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name)
|
|
||||||
.Select(propName => typeof(TEntity).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList();
|
|
||||||
|
|
||||||
Func<TEntity, TEntity> func = updateFactory.Compile();
|
|
||||||
|
|
||||||
TEntity applyObj = func(waitModifyEntity);
|
|
||||||
|
|
||||||
//深拷贝更新之前实体信息
|
|
||||||
//var copyObj = waitModifyEntity.Clone();
|
|
||||||
|
|
||||||
foreach (PropertyInfo prop in list)
|
|
||||||
{
|
|
||||||
object value = prop.GetValue(applyObj);
|
|
||||||
prop.SetValue(waitModifyEntity, value);
|
|
||||||
|
|
||||||
_dbContext.Entry(waitModifyEntity).Property(prop.Name).IsModified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>EF跟踪方式 删除</summary>
|
/// <summary>EF跟踪方式 删除</summary>
|
||||||
|
@ -368,7 +309,9 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
/// <summary>批量删除,相当于原生sql, 没用EF跟踪方式(所有查询出来,再删除 浪费性能)</summary>
|
/// <summary>批量删除,相当于原生sql, 没用EF跟踪方式(所有查询出来,再删除 浪费性能)</summary>
|
||||||
public async Task<bool> BatchDeleteNoTrackingAsync(Expression<Func<TEntity, bool>> deleteFilter)
|
public async Task<bool> BatchDeleteNoTrackingAsync(Expression<Func<TEntity, bool>> deleteFilter)
|
||||||
{
|
{
|
||||||
return await _dbSet.IgnoreQueryFilters().Where(deleteFilter).BatchDeleteAsync() > 0;
|
|
||||||
|
return await _dbContext.BatchDeleteNoTrackingAsync(deleteFilter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -377,42 +320,15 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
Expression<Func<TEntity, TEntity>> updateFactory)
|
Expression<Func<TEntity, TEntity>> updateFactory)
|
||||||
{
|
{
|
||||||
|
|
||||||
var bindings = ((MemberInitExpression)updateFactory.Body).Bindings.ToList();
|
return await _dbContext.BatchUpdateNoTrackingAsync(where, updateFactory,_userInfo.Id);
|
||||||
|
|
||||||
var hasPropNameList = bindings.Select(t => t.Member.Name).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
if (typeof(IAuditUpdate).IsAssignableFrom(typeof(TEntity)))
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateTime)))
|
|
||||||
{
|
|
||||||
bindings.Add(Expression.Bind(typeof(TEntity).GetMember(nameof(IAuditUpdate.UpdateTime))[0], Expression.Constant(DateTime.Now)));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateUserId)))
|
|
||||||
{
|
|
||||||
bindings.Add(Expression.Bind(typeof(TEntity).GetMember(nameof(IAuditUpdate.UpdateUserId))[0], Expression.Constant(_userInfo.Id)));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var member = Expression.MemberInit(Expression.New(typeof(TEntity)), bindings);
|
|
||||||
|
|
||||||
var factory = Expression.Lambda<Func<TEntity, TEntity>>(member, Expression.Parameter(typeof(TEntity), "x"));
|
|
||||||
|
|
||||||
|
|
||||||
return await _dbSet.IgnoreQueryFilters().Where(where).BatchUpdateAsync(factory) > 0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 保存 、忽略 、验证
|
#region 保存 、忽略 、验证
|
||||||
public async Task<TEntity> InsertOrUpdateAsync<TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
|
public async Task<TEntity> InsertOrUpdateAsync<TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
|
||||||
{
|
{
|
||||||
|
@ -428,41 +344,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
return await UpdateFromDTOAsync(from, autoSave, false, verify);
|
return await UpdateFromDTOAsync(from, autoSave, false, verify);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async Task EntityVerifyAsync(bool isAdd, EntityVerifyExp<TEntity>[] verify, Guid? entitydId = null)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (isAdd)
|
|
||||||
{
|
|
||||||
foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyUpdate && t.IsVerify))
|
|
||||||
{
|
|
||||||
if (await _dbSet.AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyAdd && t.IsVerify))
|
|
||||||
{
|
|
||||||
if (verifyItem.verifyType == VerifyEnum.OnlyUpdate)
|
|
||||||
{
|
|
||||||
if (await _dbSet.AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (verifyItem.verifyType == VerifyEnum.Both)
|
|
||||||
{
|
|
||||||
if (await _dbSet.AnyAsync(verifyItem.VerifyExp.And(t => t.Id != entitydId)).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> SaveChangesAsync(bool autoSave)
|
private async Task<bool> SaveChangesAsync(bool autoSave)
|
||||||
{
|
{
|
||||||
|
@ -523,7 +405,8 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
public async Task<TEntity> UpdatePartialFieldsAsync(TEntity entity, string[] propertyNames,
|
public async Task<TEntity> UpdatePartialFieldsAsync(TEntity entity, string[] propertyNames,
|
||||||
bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
|
bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
|
||||||
{
|
{
|
||||||
await EntityVerifyAsync(false, verify, entity.Id);
|
|
||||||
|
await _dbContext.EntityVerifyAsync(false, verify, entity.Id);
|
||||||
|
|
||||||
var entityEntry = _dbContext.Entry(entity);
|
var entityEntry = _dbContext.Entry(entity);
|
||||||
entityEntry.State = EntityState.Detached;
|
entityEntry.State = EntityState.Detached;
|
||||||
|
@ -543,8 +426,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
/// <summary>更新 排除某些字段的更新 排除方式: new[] {nameof(User.Name), nameof(User.Age)</summary>
|
/// <summary>更新 排除某些字段的更新 排除方式: new[] {nameof(User.Name), nameof(User.Age)</summary>
|
||||||
public async Task<TEntity> UpdateExcludeFields(TEntity entity, string[] propertyNames, bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
|
public async Task<TEntity> UpdateExcludeFields(TEntity entity, string[] propertyNames, bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
|
||||||
{
|
{
|
||||||
|
await _dbContext.EntityVerifyAsync(false, verify, entity.Id);
|
||||||
await EntityVerifyAsync(false, verify, entity.Id);
|
|
||||||
|
|
||||||
var entityEntry = _dbContext.Entry(entity);
|
var entityEntry = _dbContext.Entry(entity);
|
||||||
entityEntry.State = EntityState.Modified;
|
entityEntry.State = EntityState.Modified;
|
||||||
|
@ -611,7 +493,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> exp = null, bool isTracking = false)
|
public async Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> exp = null, bool isTracking = false, bool ignoreQueryFilters = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
var query = _dbSet.AsQueryable();
|
var query = _dbSet.AsQueryable();
|
||||||
|
@ -621,6 +503,11 @@ namespace IRaCIS.Core.Infra.EFCore
|
||||||
query = query.AsNoTracking();
|
query = query.AsNoTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ignoreQueryFilters)
|
||||||
|
{
|
||||||
|
query = query.IgnoreQueryFilters();
|
||||||
|
}
|
||||||
|
|
||||||
var entity = await query.FirstOrDefaultAsync();
|
var entity = await query.FirstOrDefaultAsync();
|
||||||
|
|
||||||
if (entity is null)
|
if (entity is null)
|
||||||
|
|
Loading…
Reference in New Issue