修改仓储批量更新和批量删除方法

This commit is contained in:
2022-04-19 09:01:59 +08:00
parent 7c1fdde2f3
commit eda7ac40bf
53 changed files with 316 additions and 254 deletions
@@ -37,8 +37,6 @@ namespace IRaCIS.Core.Infra.EFCore
optionsBuilder.UseLoggerFactory(MyLoggerFactory)
.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactoryDesignTimeSupport>();
optionsBuilder.UseBatchEF_MSSQL();
//var config = new ConfigurationBuilder()
// .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).Build();
//connectionString = config.GetSection("ConnectionStrings:RemoteNew").Value;
@@ -27,7 +27,6 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="6.13.6" />
<PackageReference Include="Zack.EFCore.Batch.MSSQL_NET6" Version="6.0.12" />
</ItemGroup>
</Project>
@@ -23,10 +23,8 @@ namespace IRaCIS.Core.Infra.EFCore
Task<TEntity> UpdatePartialFields(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify);
Task<bool> BatchUpdateAsync(Expression<Func<TEntity, bool>> where,
Expression<Func<TEntity, TEntity>> updateFactory);
Task<bool> BatchDeleteAsync(Expression<Func<TEntity, bool>> deleteFilter);
Task<bool> BatchUpdateAsync(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TEntity>> updateFactory);
}
@@ -56,8 +54,7 @@ namespace IRaCIS.Core.Infra.EFCore
Task<bool> DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default);
Task<bool> DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default);
Task<bool> DeleteFromQueryAsync(Expression<Func<TEntity, bool>> deleteFilter) ;
Task<bool> UpdateFromQueryAsync(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TEntity>> updateFactory);
}
@@ -11,6 +11,8 @@ 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
{
@@ -59,9 +61,9 @@ namespace IRaCIS.Core.Infra.EFCore
Task<bool> SaveChangesAsync();
Task<bool> DeleteFromQueryAsync<T>(Expression<Func<T, bool>> deleteFilter) where T : Entity;
Task<bool> BatchDeleteAsync<T>(Expression<Func<T, bool>> deleteFilter) where T : Entity;
Task<bool> UpdateFromQueryAsync<T>(Expression<Func<T, bool>> where, Expression<Func<T, T>> updateFactory) where T : Entity;
Task<bool> BatchUpdateAsync<T>(Expression<Func<T, bool>> where, Expression<Func<T, T>> updateFactory) where T : Entity;
}
public class Repository : IRepository
@@ -70,10 +72,13 @@ namespace IRaCIS.Core.Infra.EFCore
public IMapper _mapper { get; set; }
public Repository(IRaCISDBContext dbContext, IMapper mapper)
public IUserInfo _userInfo { get; set; }
public Repository(IRaCISDBContext dbContext, IMapper mapper, IUserInfo userInfo)
{
_dbContext = dbContext;
_mapper = mapper;
_userInfo = userInfo;
}
/// <summary>
@@ -396,18 +401,32 @@ namespace IRaCIS.Core.Infra.EFCore
#endregion
public async Task<bool> DeleteFromQueryAsync<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.Set<T>().AsNoTracking().Where(deleteFilter).DeleteFromQueryAsync().ConfigureAwait(false) > 0;
return await _dbContext.Set<T>().AsNoTracking().Where(deleteFilter).BatchDeleteAsync().ConfigureAwait(false) > 0;
}
public async Task<bool> UpdateFromQueryAsync<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));
return await _dbContext.Set<T>().AsNoTracking().IgnoreQueryFilters().Where(whereFilter).UpdateFromQueryAsync(updateFactory).ConfigureAwait(false) > 0;
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;
}
}
+104 -53
View File
@@ -13,6 +13,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using AutoMapper.QueryableExtensions;
using EFCore.BulkExtensions;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.Data.SqlClient;
@@ -28,11 +29,13 @@ namespace IRaCIS.Core.Infra.EFCore
public DbSet<TEntity> _dbSet => _dbContext.Set<TEntity>();
public IUserInfo _userInfo { get; set; }
public Repository(IRaCISDBContext dbContext, IMapper mapper)
public Repository(IRaCISDBContext dbContext, IMapper mapper,IUserInfo userInfo)
{
_dbContext = dbContext;
_mapper = mapper;
_userInfo = userInfo;
}
#region
@@ -155,6 +158,16 @@ namespace IRaCIS.Core.Infra.EFCore
}
/// <summary>
/// 用前端传递的视图模型字段,更新,同时返回数据库该条记录的原始信息,方便对比某些字段是否更改,进行相应的逻辑操作
/// </summary>
/// <typeparam name="TFrom"></typeparam>
/// <param name="from"></param>
/// <param name="autoSave"></param>
/// <param name="ignoreDtoNullProperty"></param>
/// <param name="verify"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
public async Task<TEntity> UpdateFromDTOAsync<TFrom>(TFrom from, bool autoSave = false, bool ignoreDtoNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
{
@@ -180,9 +193,10 @@ namespace IRaCIS.Core.Infra.EFCore
// Guid?属性 为null 时 映射到 Guid 时 默认会变成 Guid.Empty
if (ignoreDtoNullProperty)
{
var dbEntityProp = typeof(TEntity).GetProperties();
foreach (var propertyInfo in from.GetType().GetProperties())
{
if (propertyInfo.GetValue(from) == null)
if (propertyInfo.GetValue(from) == null && dbEntityProp.Any(t=>t.Name== propertyInfo.Name))
{
_dbContext.Entry(dbEntity).Property(propertyInfo.Name).IsModified = false;
}
@@ -196,46 +210,6 @@ namespace IRaCIS.Core.Infra.EFCore
}
/// <summary>
/// 通过主键id 和表达式树 更新部分字段 例如 Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584"),u => new Dictionary() { ParentId = null, Code = "test" } 默认会去处理更新更新人 更新时间
/// </summary>
/// <param name="id"></param>
/// <param name="updateFactory"></param>
/// <param name="autoSave"></param>
/// <param name="verify"></param>
/// <returns></returns>
public async Task<TEntity> UpdatePartialFields(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
{
await EntityVerifyAsync(false, verify, id);
var entity = new TEntity() { Id = id };
var entityEntry = _dbContext.Entry(entity);
entityEntry.State = EntityState.Detached;
Func<TEntity, TEntity> func = updateFactory.Compile();
List<PropertyInfo> list = ((MemberInitExpression)updateFactory.Body).Bindings.Select<MemberBinding, string>((Func<MemberBinding, string>)(_param1 => _param1.Member.Name)).Select<string, PropertyInfo>((Func<string, PropertyInfo>)(_param1 => (PropertyInfo)typeof(TEntity).GetProperty(_param1, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))).ToList<PropertyInfo>();
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;
}
await SaveChangesAsync(autoSave);
return entityEntry.Entity;
}
private async Task<bool> SaveChangesAsync(bool autoSave)
{
if (autoSave)
@@ -248,8 +222,65 @@ namespace IRaCIS.Core.Infra.EFCore
}
}
/// <summary>
/// 通过主键id 和表达式树 更新部分字段 例如 Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584"),u => new Dictionary() { ParentId = null, Code = "test" } 默认会去处理更新更新人 更新时间
/// </summary>
/// <param name="id"></param>
/// <param name="updateFactory"></param>
/// <param name="autoSave"></param>
/// <param name="verify"></param>
/// <returns></returns>
public async Task<TEntity> UpdatePartialFields(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, 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;
}
await SaveChangesAsync(autoSave);
return entityEntry.Entity;
#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
}
/// <summary>
/// 部分字段更新 (只更新传递的字段名 new[] {nameof(User.Name), nameof(User.Age))
/// new Dictionary() { ParentId = null, Code = "test"Id=Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584")},new[] {nameof(Dictionary.Name), nameof(Dictionary.Age))
/// </summary>
/// <param name="entity"></param>
/// <param name="propertyNames"> 更新的字段数组 </param>
@@ -501,16 +532,6 @@ namespace IRaCIS.Core.Infra.EFCore
return whereLambda == null ? await query.AsNoTracking().CountAsync() : await query.AsNoTracking().CountAsync(whereLambda);
}
// Z.EntityFramework.Plus.EFCore
public async Task<bool> DeleteFromQueryAsync(Expression<Func<TEntity, bool>> deleteFilter)
{
return await _dbSet.IgnoreQueryFilters().Where(deleteFilter).DeleteFromQueryAsync() > 0;
}
public async Task<bool> UpdateFromQueryAsync(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TEntity>> updateFactory)
{
return await _dbSet.IgnoreQueryFilters().Where(where).UpdateFromQueryAsync(updateFactory) > 0;
}
public async Task<bool> BatchDeleteAsync(Expression<Func<TEntity, bool>> deleteFilter)
@@ -523,7 +544,27 @@ namespace IRaCIS.Core.Infra.EFCore
Expression<Func<TEntity, TEntity>> updateFactory)
{
return await _dbSet.IgnoreQueryFilters().Where(where).BatchUpdateAsync(updateFactory) > 0;
//return await _dbSet.IgnoreQueryFilters().Where(where).BatchUpdateAsync(updateFactory) > 0;
var bindings = ((MemberInitExpression)updateFactory.Body).Bindings.ToList();
if (typeof(IAuditUpdate).IsAssignableFrom(typeof(TEntity)))
{
bindings.Add(Expression.Bind(typeof(TEntity).GetMember(nameof(IAuditUpdate.UpdateTime))[0], Expression.Constant(DateTime.Now)));
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;
}
@@ -570,6 +611,16 @@ namespace IRaCIS.Core.Infra.EFCore
// return await builder.Where(where).ExecuteAsync()>0;
//}
//// Z.EntityFramework.Plus.EFCore
//public async Task<bool> BatchDeleteAsync(Expression<Func<TEntity, bool>> deleteFilter)
//{
// return await _dbSet.IgnoreQueryFilters().Where(deleteFilter).DeleteFromQueryAsync() > 0;
//}
//public async Task<bool> BatchUpdateAsync(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TEntity>> updateFactory)
//{
// return await _dbSet.IgnoreQueryFilters().Where(where).UpdateFromQueryAsync(updateFactory) > 0;
//}
#endregion