ABP框架6.0后提供了 InsertManyAsync  UpdateManyAsync DeleteManyAsync  批量操作方法

源码:

public interface IBasicRepository<TEntity> : IReadOnlyBasicRepository<TEntity>, IRepository
   where TEntity : class, IEntity
{
    Task<TEntity> InsertAsync(
      TEntity entity,
      bool autoSave = false,
      CancellationToken cancellationToken = default(CancellationToken));
    
    Task InsertManyAsync(
      IEnumerable<TEntity> entities,
      bool autoSave = false,
      CancellationToken cancellationToken = default(CancellationToken));
    
    Task<TEntity> UpdateAsync(
      TEntity entity,
      bool autoSave = false,
      CancellationToken cancellationToken = default(CancellationToken));
    
    Task UpdateManyAsync(
      IEnumerable<TEntity> entities,
      bool autoSave = false,
      CancellationToken cancellationToken = default(CancellationToken));

    Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default(CancellationToken));
    
    Task DeleteManyAsync(
      IEnumerable<TEntity> entities,
      bool autoSave = false,
      CancellationToken cancellationToken = default(CancellationToken));
}

  我们的IRepository接口是继承自IBasicRepository接口的

 public interface IRepository<TEntity> : 
    IReadOnlyRepository<TEntity>,
    IReadOnlyBasicRepository<TEntity>,
    IRepository,
    IBasicRepository<TEntity>
    where TEntity : class, IEntity

我们一般在**EntityFrameworkCoreModule 层注入一个默认的仓储接口实现

 context.Services.AddAbpDbContext<HolidayDbContext>(options =>
        {
                /* Remove "includeAllEntities: true" to create
                 * default repositories only for aggregate roots */
            options.AddDefaultRepositories(includeAllEntities: true);
        });

默认实现类

public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IEfCoreRepository<TEntity>
    where TDbContext : IEfCoreDbContext
    where TEntity : class, IEntity

在此类实现了 InsertManyAsync  UpdateManyAsync DeleteManyAsync 方法

源码

    public override async Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        var entityArray = entities.ToArray();
        var dbContext = await GetDbContextAsync();
        cancellationToken = GetCancellationToken(cancellationToken);

        foreach (var entity in entityArray)
        {
            CheckAndSetId(entity);
        }

        if (BulkOperationProvider != null)
        {
            await BulkOperationProvider.InsertManyAsync<TDbContext, TEntity>(
                this,
                entityArray,
                autoSave,
                GetCancellationToken(cancellationToken)
            );
            return;
        }

        await dbContext.Set<TEntity>().AddRangeAsync(entityArray, cancellationToken);

        if (autoSave)
        {
            await dbContext.SaveChangesAsync(cancellationToken);
        }
    }
    public override async Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        cancellationToken = GetCancellationToken(cancellationToken);

        if (BulkOperationProvider != null)
        {
            await BulkOperationProvider.UpdateManyAsync<TDbContext, TEntity>(
                this,
                entities,
                autoSave,
                GetCancellationToken(cancellationToken)
                );

            return;
        }

        var dbContext = await GetDbContextAsync();

        dbContext.Set<TEntity>().UpdateRange(entities);

        if (autoSave)
        {
            await dbContext.SaveChangesAsync(cancellationToken);
        }
    }
  public override async Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
    {
        cancellationToken = GetCancellationToken(cancellationToken);

        if (BulkOperationProvider != null)
        {
            await BulkOperationProvider.DeleteManyAsync<TDbContext, TEntity>(
                this,
                entities,
                autoSave,
                cancellationToken
            );

            return;
        }

        var dbContext = await GetDbContextAsync();

        dbContext.RemoveRange(entities);

        if (autoSave)
        {
            await dbContext.SaveChangesAsync(cancellationToken);
        }
    }
public IEfCoreBulkOperationProvider BulkOperationProvider => LazyServiceProvider.LazyGetService<IEfCoreBulkOperationProvider>();

代码中的 BulkOperationProvider 就非常关键了 这个就是官方文档上提供的 自定义批量操作 

ABP官方原话

如果你有更好的逻辑或使用外部库实现批量操作, 你可以通过实现 IEfCoreBulkOperationProvider 覆写这个逻辑.

  • 你可以使用下面的示例模板
public class MyCustomEfCoreBulkOperationProvider
    : IEfCoreBulkOperationProvider, ITransientDependency
{
    public async Task DeleteManyAsync<TDbContext, TEntity>(
        IEfCoreRepository<TEntity> repository,
        IEnumerable<TEntity> entities,
        bool autoSave,
        CancellationToken cancellationToken)
        where TDbContext : IEfCoreDbContext
        where TEntity : class, IEntity
    {
        // Your logic here.
    }

    public async Task InsertManyAsync<TDbContext, TEntity>(
        IEfCoreRepository<TEntity> repository,
        IEnumerable<TEntity> entities,
        bool autoSave,
        CancellationToken cancellationToken)
        where TDbContext : IEfCoreDbContext
        where TEntity : class, IEntity
    {
        // Your logic here.
    }

    public async Task UpdateManyAsync<TDbContext, TEntity>(
        IEfCoreRepository<TEntity> repository,
        IEnumerable<TEntity> entities,
        bool autoSave,
        CancellationToken cancellationToken)
        where TDbContext : IEfCoreDbContext
        where TEntity : class, IEntity
    {
        // Your logic here.
    }
}

官网文档地址 https://docs.abp.io/zh-Hans/abp/latest/Entity-Framework-Core

在实际项目中,不可避免会遇到数据导入的需求,如果是大量数据导入,就必须引用批量处理的功能;efcore本身不提供批量处理功能,而abp框架虽然提供InsertMany和UpdateMany方法,但本质上仍然是分解成单条insert和update操作,在处理稍大量的数据时,耗时就会明显增加;如果你使用的是SqlServer、PostgreSQL或SQLite,可以使用官方推荐的方法实现批处理,你只需要引用borisdj / EFCore.BulkExtensions并编写IEfCoreBulkOperationProvider的提供程序即可

Install-Package EFCore.BulkExtensions
    public class BulkExtensionsEfCoreBulkOperationProvider : IEfCoreBulkOperationProvider, ITransientDependency
    {
        public BulkExtensionsEfCoreBulkOperationProvider()
        {
            
        }

        public async Task DeleteManyAsync<TDbContext, TEntity>(IEfCoreRepository<TEntity> repository, IEnumerable<TEntity> entities, bool autoSave, CancellationToken cancellationToken)
            where TDbContext : IEfCoreDbContext
            where TEntity : class, IEntity
        {
            var dbContext = await repository.GetDbContextAsync();
            await dbContext.BulkDeleteAsync(entities.ToList(), cancellationToken: cancellationToken);
        }
 
        public async Task InsertManyAsync<TDbContext, TEntity>(IEfCoreRepository<TEntity> repository, IEnumerable<TEntity> entities, bool autoSave, CancellationToken cancellationToken)
            where TDbContext : IEfCoreDbContext
            where TEntity : class, IEntity
        {
            var dbContext = await repository.GetDbContextAsync();
            await dbContext.BulkInsertAsync(entities.ToList(), cancellationToken: cancellationToken);
        }
 
        public async Task UpdateManyAsync<TDbContext, TEntity>(IEfCoreRepository<TEntity> repository, IEnumerable<TEntity> entities, bool autoSave, CancellationToken cancellationToken)
            where TDbContext : IEfCoreDbContext
            where TEntity : class, IEntity
        {
            var dbContext = await repository.GetDbContextAsync();
            await dbContext.BulkUpdateAsync(entities.ToList(), cancellationToken: cancellationToken);
        }
    }

这样常规调用InsertManyAsync或UpdateManyAsync时就可以实现批量操作。但是borisdj / EFCore.BulkExtensions不支持Mysql数据(注意:在6.0以后的版本已经支持Mysql),因此不能使用这种方法,这里我使用的是另一个扩展包yang-er/efcore-ext,跟EFCore.BulkExtensions算是一脉相承,并且添加了对mysql的支持,理论上也可以跟上面一样编写提供程序来实现,但是由于实现原理有点不一样,这样写生成不了Sql语句,还是只能换一个思路来实现了。

开始实例演示如何在abp上使用efcore-ext扩展包:

参考文章 https://blog.csdn.net/duanzilin/article/details/123253444

 

原文地址:http://www.cnblogs.com/liuxiaoji/p/16812874.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性