• ABP 在 EntityFramework 中使用扩展实现批量操作


    注意:目前批量删除即使已继承 ISoftDelete 的情况下依然会物理删除,所以可以通过批量更新实现逻辑删除。

    调用方法:

    await projectsRepository.BatchUpdateAsync(x => new Projects { Status = 2 }, x => projectIdList.Contains(x.Id));

    以下是批量更新与删除的内部实现。

    批量删除:

    /// <summary>
    /// Deletes all matching entities permanently for given predicate
    /// </summary>
    /// <typeparam name="TEntity">Entity type</typeparam>
    /// <typeparam name="TPrimaryKey">Primary key type</typeparam>
    /// <param name="repository">Repository</param>
    /// <param name="predicate">Predicate to filter entities</param>
    /// <returns></returns>
    public static async Task<int> BatchDeleteAsync<TEntity, TPrimaryKey>([NotNull] this IRepository<TEntity, TPrimaryKey> repository, [NotNull] Expression<Func<TEntity, bool>> predicate)
        where TEntity : Entity<TPrimaryKey>
    {
        Check.NotNull(repository, nameof(repository));
        Check.NotNull(predicate, nameof(predicate));
    
        var query = repository.GetAll().IgnoreQueryFilters();
    
        var abpFilterExpression = GetFilterExpressionOrNull<TEntity, TPrimaryKey>(repository.GetIocResolver());
        var filterExpression = ExpressionCombiner.Combine(predicate, abpFilterExpression);
    
        query = query.Where(filterExpression);
    
        return await query.DeleteAsync();
    }

    批量更新:

    /// <summary>
    /// Updates all matching entities using given updateExpression for given predicate
    /// </summary>
    /// <typeparam name="TEntity">Entity type</typeparam>
    /// <typeparam name="TPrimaryKey">Primary key type</typeparam>
    /// <param name="repository">Repository</param>
    /// /// <param name="updateExpression">Update expression</param>
    /// <param name="predicate">Predicate to filter entities</param>
    /// <returns></returns>
    public static async Task<int> BatchUpdateAsync<TEntity, TPrimaryKey>([NotNull]this IRepository<TEntity, TPrimaryKey> repository, [NotNull]Expression<Func<TEntity, TEntity>> updateExpression, [NotNull]Expression<Func<TEntity, bool>> predicate)
        where TEntity : Entity<TPrimaryKey>
    {
        Check.NotNull(repository, nameof(repository));
        Check.NotNull(updateExpression, nameof(updateExpression));
        Check.NotNull(predicate, nameof(predicate));
    
        var query = repository.GetAll().IgnoreQueryFilters();
    
        var abpFilterExpression = GetFilterExpressionOrNull<TEntity, TPrimaryKey>(repository.GetIocResolver());
        var filterExpression = ExpressionCombiner.Combine(predicate, abpFilterExpression);
    
        query = query.Where(filterExpression);
    
        return await query.UpdateAsync(updateExpression);
    }

    ABP 扩展类内部实现:

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Threading.Tasks;
    using Abp.Dependency;
    using Abp.Domain.Entities;
    using Abp.Domain.Repositories;
    using Abp.Domain.Uow;
    using Abp.Linq.Expressions;
    using Abp.Runtime.Session;
    using JetBrains.Annotations;
    using Microsoft.EntityFrameworkCore;
    using Z.EntityFramework.Plus;
    
    namespace Abp.EntityFrameworkCore.EFPlus
    {
        /// <summary>
        /// Defines batch delete and update extension methods for IRepository
        /// </summary>
        public static class AbpEntityFrameworkCoreEfPlusExtensions
        {
            /// <summary>
            /// Deletes all matching entities permanently for given predicate
            /// </summary>
            /// <typeparam name="TEntity">Entity type</typeparam>
            /// <typeparam name="TPrimaryKey">Primary key type</typeparam>
            /// <param name="repository">Repository</param>
            /// <param name="predicate">Predicate to filter entities</param>
            /// <returns></returns>
            public static async Task<int> BatchDeleteAsync<TEntity, TPrimaryKey>([NotNull] this IRepository<TEntity, TPrimaryKey> repository, [NotNull] Expression<Func<TEntity, bool>> predicate)
                where TEntity : Entity<TPrimaryKey>
            {
                Check.NotNull(repository, nameof(repository));
                Check.NotNull(predicate, nameof(predicate));
    
                var query = repository.GetAll().IgnoreQueryFilters();
    
                var abpFilterExpression = GetFilterExpressionOrNull<TEntity, TPrimaryKey>(repository.GetIocResolver());
                var filterExpression = ExpressionCombiner.Combine(predicate, abpFilterExpression);
    
                query = query.Where(filterExpression);
    
                return await query.DeleteAsync();
            }
    
            /// <summary>
            /// Deletes all matching entities permanently for given predicate
            /// </summary>
            /// <typeparam name="TEntity">Entity type</typeparam>
            /// <param name="repository">Repository</param>
            /// <param name="predicate">Predicate to filter entities</param>
            /// <returns></returns>
            public static async Task<int> BatchDeleteAsync<TEntity>([NotNull] this IRepository<TEntity> repository, [NotNull]Expression<Func<TEntity, bool>> predicate)
                where TEntity : Entity<int>
            {
                return await repository.BatchDeleteAsync<TEntity, int>(predicate);
            }
    
            /// <summary>
            /// Updates all matching entities using given updateExpression for given predicate
            /// </summary>
            /// <typeparam name="TEntity">Entity type</typeparam>
            /// <typeparam name="TPrimaryKey">Primary key type</typeparam>
            /// <param name="repository">Repository</param>
            /// /// <param name="updateExpression">Update expression</param>
            /// <param name="predicate">Predicate to filter entities</param>
            /// <returns></returns>
            public static async Task<int> BatchUpdateAsync<TEntity, TPrimaryKey>([NotNull]this IRepository<TEntity, TPrimaryKey> repository, [NotNull]Expression<Func<TEntity, TEntity>> updateExpression, [NotNull]Expression<Func<TEntity, bool>> predicate)
                where TEntity : Entity<TPrimaryKey>
            {
                Check.NotNull(repository, nameof(repository));
                Check.NotNull(updateExpression, nameof(updateExpression));
                Check.NotNull(predicate, nameof(predicate));
    
                var query = repository.GetAll().IgnoreQueryFilters();
    
                var abpFilterExpression = GetFilterExpressionOrNull<TEntity, TPrimaryKey>(repository.GetIocResolver());
                var filterExpression = ExpressionCombiner.Combine(predicate, abpFilterExpression);
    
                query = query.Where(filterExpression);
    
                return await query.UpdateAsync(updateExpression);
            }
    
            /// <summary>
            /// Updates all matching entities using given updateExpression for given predicate
            /// </summary>
            /// <typeparam name="TEntity">Entity type</typeparam>
            /// <param name="repository">Repository</param>
            /// /// <param name="updateExpression">Update expression</param>
            /// <param name="predicate">Predicate to filter entities</param>
            /// <returns></returns>
            public static async Task<int> BatchUpdateAsync<TEntity>(
                [NotNull]this IRepository<TEntity> repository, [NotNull]Expression<Func<TEntity, TEntity>> updateExpression,
                [NotNull]Expression<Func<TEntity, bool>> predicate)
                where TEntity : Entity<int>
            {
                return await repository.BatchUpdateAsync<TEntity, int>(updateExpression, predicate);
            }
    
            private static Expression<Func<TEntity, bool>> GetFilterExpressionOrNull<TEntity, TPrimaryKey>(IIocResolver iocResolver) where TEntity : Entity<TPrimaryKey>
            {
                Expression<Func<TEntity, bool>> expression = null;
    
                using (var scope = iocResolver.CreateScope())
                {
                    var currentUnitOfWorkProvider = scope.Resolve<ICurrentUnitOfWorkProvider>();
    
                    if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
                    {
                        var isSoftDeleteFilterEnabled = currentUnitOfWorkProvider.Current?.IsFilterEnabled(AbpDataFilters.SoftDelete) == true;
                        if (isSoftDeleteFilterEnabled)
                        {
                            Expression<Func<TEntity, bool>> softDeleteFilter = e => !((ISoftDelete)e).IsDeleted;
                            expression = softDeleteFilter;
                        }
                    }
    
                    if (typeof(IMayHaveTenant).IsAssignableFrom(typeof(TEntity)))
                    {
                        var isMayHaveTenantFilterEnabled = currentUnitOfWorkProvider.Current?.IsFilterEnabled(AbpDataFilters.MayHaveTenant) == true;
                        var currentTenantId = GetCurrentTenantIdOrNull(iocResolver);
    
                        if (isMayHaveTenantFilterEnabled)
                        {
                            Expression<Func<TEntity, bool>> mayHaveTenantFilter = e => ((IMayHaveTenant)e).TenantId == currentTenantId;
                            expression = expression == null ? mayHaveTenantFilter : ExpressionCombiner.Combine(expression, mayHaveTenantFilter);
                        }
                    }
    
                    if (typeof(IMustHaveTenant).IsAssignableFrom(typeof(TEntity)))
                    {
                        var isMustHaveTenantFilterEnabled = currentUnitOfWorkProvider.Current?.IsFilterEnabled(AbpDataFilters.MustHaveTenant) == true;
                        var currentTenantId = GetCurrentTenantIdOrNull(iocResolver);
    
                        if (isMustHaveTenantFilterEnabled)
                        {
                            Expression<Func<TEntity, bool>> mustHaveTenantFilter = e => ((IMustHaveTenant)e).TenantId == currentTenantId;
                            expression = expression == null ? mustHaveTenantFilter : ExpressionCombiner.Combine(expression, mustHaveTenantFilter);
                        }
                    }
                }
    
                return expression;
            }
    
            private static int? GetCurrentTenantIdOrNull(IIocResolver iocResolver)
            {
                using (var scope = iocResolver.CreateScope())
                {
                    var currentUnitOfWorkProvider = scope.Resolve<ICurrentUnitOfWorkProvider>();
    
                    if (currentUnitOfWorkProvider?.Current != null)
                    {
                        return currentUnitOfWorkProvider.Current.GetTenantId();
                    }
    
                    return iocResolver.Resolve<IAbpSession>().TenantId;
                }
            }
        }
    }
    
  • 相关阅读:
    QFramework Pro 开发日志(一)随便写点啥,3 月开始整活了。
    QFramework Pro 开发日志(六)一键生成类图功能介绍
    QFramework Pro 开发日志(二)为啥要搞 Pro
    乡亲们,我们创建了 Dapr 中文交流频道
    学大数据要考什么证书吗?2022软考备考群已成立!
    元数据管理为什么需要统一的元模型?
    美团外卖实时数仓方案整理
    巧用 Base62 解决字段太短的问题
    千万级支付对账系统怎么玩(下篇)?
    千万级支付对账系统怎么玩(上篇)?
  • 原文地址:https://www.cnblogs.com/fxck/p/13076717.html
Copyright © 2020-2023  润新知