215 lines
7.9 KiB
C#
215 lines
7.9 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public static async Task EntityVerifyAsync<T>(this IRepository<T> _entityRepository, Guid? entitydId = null,params EntityVerifyExp<T>[] verify) where T : Entity
|
||
{
|
||
|
||
if (entitydId==null)
|
||
{
|
||
foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyUpdate && t.IsVerify))
|
||
{
|
||
if (await _entityRepository.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 _entityRepository.AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
|
||
{
|
||
throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
|
||
}
|
||
}
|
||
else if (verifyItem.verifyType == VerifyEnum.Both)
|
||
{
|
||
if (await _entityRepository.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)
|
||
{
|
||
_dbContext.Entry(waitModifyEntity).Property(prop.Name).IsModified = true;
|
||
|
||
object value = prop.GetValue(applyObj);
|
||
prop.SetValue(waitModifyEntity, value);
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
#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).ExecuteDeleteAsync() > 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
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|