整理仓储
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,
|
||||
bool autoSave = false, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary> EF跟踪方式 先查询出来,再更新部分字段 </summary>
|
||||
/// <summary> EF跟踪方式 会去数据库查询完整的实体,再更新部分字段 </summary>
|
||||
Task<TEntity> UpdatePartialFromQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
|
||||
bool autoSave = false, bool ignoreQueryFilter = false, CancellationToken cancellationToken = default);
|
||||
|
||||
|
@ -93,7 +93,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
/// <param name="exp"></param>
|
||||
/// <param name="ignoreQueryFilters"></param>
|
||||
/// <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>
|
||||
///跟踪 查询单个实体,会出现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
|
||||
{
|
||||
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;
|
||||
EntityEntry<T> Entry<T>(T t) where T : Entity;
|
||||
|
||||
|
@ -92,15 +92,15 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
/// <param name="isTraking"></param>
|
||||
/// <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>();
|
||||
|
||||
if (!isTraking)
|
||||
if (ignoreQueryFilters)
|
||||
{
|
||||
query = query.AsNoTracking();
|
||||
query = query.IgnoreQueryFilters();
|
||||
}
|
||||
return query;
|
||||
return query.AsNoTracking();
|
||||
}
|
||||
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,
|
||||
params EntityVerifyExp<T>[] verify) where T : Entity
|
||||
{
|
||||
|
||||
var entity = _mapper.Map<T>(from);
|
||||
|
||||
await EntityVerifyAsync(true, verify);
|
||||
await _dbContext.EntityVerifyAsync(true, verify);
|
||||
|
||||
entity = await AddAsync(entity, autoSave);
|
||||
|
||||
|
@ -195,7 +159,8 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
{
|
||||
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);
|
||||
|
||||
|
@ -359,10 +324,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
await _dbContext.Set<T>().AddAsync(entity).ConfigureAwait(false);
|
||||
|
||||
if (autoSave)
|
||||
{
|
||||
await SaveChangesAsync();
|
||||
}
|
||||
await SaveChangesAsync(autoSave);
|
||||
|
||||
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
|
||||
{
|
||||
if (deleteFilter == null) throw new ArgumentNullException(nameof(deleteFilter));
|
||||
|
||||
return await _dbContext.Set<T>().AsNoTracking().IgnoreQueryFilters().Where(deleteFilter).BatchDeleteAsync().ConfigureAwait(false) > 0;
|
||||
return await _dbContext.BatchDeleteNoTrackingAsync(deleteFilter);
|
||||
}
|
||||
|
||||
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)))
|
||||
{
|
||||
|
||||
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;
|
||||
return await _dbContext.BatchUpdateNoTrackingAsync(whereFilter, updateFactory, _userInfo.Id);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -464,46 +399,22 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
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
|
||||
{
|
||||
var entityEntry = _dbContext.Entry(waitModifyEntity);
|
||||
entityEntry.State = EntityState.Detached;
|
||||
|
||||
|
||||
ModifyPartialFiled(waitModifyEntity, updateFactory);
|
||||
|
||||
_dbContext.EntityModifyPartialFiled(waitModifyEntity, updateFactory);
|
||||
|
||||
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
|
||||
|
|
|
@ -43,6 +43,8 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#region 异步 EF 跟踪 添加
|
||||
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)
|
||||
{
|
||||
|
||||
await EntityVerifyAsync(true, verify);
|
||||
await _dbContext.EntityVerifyAsync(true, verify);
|
||||
|
||||
var entity = _mapper.Map<TEntity>(from);
|
||||
|
||||
|
@ -93,7 +95,9 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
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);
|
||||
|
||||
|
@ -131,12 +135,18 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
|
||||
|
||||
/// <summary> EF跟踪方式 生成 部分字段更新, 通过主键id 和表达式树 更新部分字段
|
||||
/// 例如 Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584"),u => new Dictionary() { ParentId = null, Code = "test" }默认会去处理更新更新人 更新时间</summary>
|
||||
/// <summary> EF跟踪方式 生成 部分字段更新, 跟踪的实体仅有修改的属性的值有具体意义,没有从数据库查询完整的实体</summary>
|
||||
|
||||
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);
|
||||
|
||||
|
@ -147,52 +157,16 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
public async Task<bool> UpdatePartialNowNoQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <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
|
||||
|
@ -206,25 +180,15 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
{
|
||||
_dbSet.Update(entity);
|
||||
|
||||
if (autoSave)
|
||||
{
|
||||
return await SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return await SaveChangesAsync(autoSave);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>EF跟踪方式 外层先有查询好的完成实体,再更新部分字段 稽查的时候需要完整的实体信息</summary>
|
||||
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;
|
||||
|
||||
|
||||
ModifyPartialFiled(waitModifyEntity, updateFactory);
|
||||
_dbContext.EntityModifyPartialFiled(waitModifyEntity, updateFactory);
|
||||
|
||||
return await SaveChangesAsync(autoSave);
|
||||
|
||||
|
@ -238,7 +202,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
var query = ignoreQueryFilter ? _dbSet.AsNoTracking().IgnoreQueryFilters() : _dbSet.AsNoTracking();
|
||||
//不跟踪 查询出来的实体就是Detached
|
||||
var searchEntity = await query.IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == id);
|
||||
var searchEntity = await query.FirstOrDefaultAsync(t => t.Id == id);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
ModifyPartialFiled(searchEntity, updateFactory);
|
||||
|
||||
_dbContext.EntityModifyPartialFiled(searchEntity, updateFactory);
|
||||
|
||||
await SaveChangesAsync(autoSave);
|
||||
|
||||
|
@ -269,35 +231,14 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
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>
|
||||
|
@ -368,7 +309,9 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
/// <summary>批量删除,相当于原生sql, 没用EF跟踪方式(所有查询出来,再删除 浪费性能)</summary>
|
||||
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)
|
||||
{
|
||||
|
||||
var bindings = ((MemberInitExpression)updateFactory.Body).Bindings.ToList();
|
||||
|
||||
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;
|
||||
|
||||
|
||||
return await _dbContext.BatchUpdateNoTrackingAsync(where, updateFactory,_userInfo.Id);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
#region 保存 、忽略 、验证
|
||||
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);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
@ -523,7 +405,8 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
public async Task<TEntity> UpdatePartialFieldsAsync(TEntity entity, string[] propertyNames,
|
||||
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);
|
||||
entityEntry.State = EntityState.Detached;
|
||||
|
@ -543,8 +426,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
/// <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)
|
||||
{
|
||||
|
||||
await EntityVerifyAsync(false, verify, entity.Id);
|
||||
await _dbContext.EntityVerifyAsync(false, verify, entity.Id);
|
||||
|
||||
var entityEntry = _dbContext.Entry(entity);
|
||||
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();
|
||||
|
@ -621,6 +503,11 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
query = query.AsNoTracking();
|
||||
}
|
||||
|
||||
if (ignoreQueryFilters)
|
||||
{
|
||||
query = query.IgnoreQueryFilters();
|
||||
}
|
||||
|
||||
var entity = await query.FirstOrDefaultAsync();
|
||||
|
||||
if (entity is null)
|
||||
|
|
Loading…
Reference in New Issue