ABP EF CORE 7 集成ShardingCore实现分表

参考文章
Abp VNext 分表分库
.Net下极限生产力之分表分库全自动化Migrations Code-First
官方文档
ShardingCore

原文是在Abp VNext的基础上做了分库分表,本文将基于ABPEF CORE 7做分表,支持分表和批量更新的系统性能应该会有一个较大的提升。

添加依赖

Install-Package ShardingCore -Version 7.0.0.5

创建实体

public class ToDoItem : AggregateRoot<long>, ISoftDelete, IMayHaveTenant, ICreationAudited, IShardingKeyIsCreationTime
{
    public bool IsDeleted { get; set; }
    public int? TenantId { get; set; }
    public long? CreatorUserId { get; set; }
    public DateTime CreationTime { get; set; }

    public string Text { get; set; }
}

//标识对应的分表对像的分表字段是id时,自动创建guid
public interface IShardingKeyIsGuId
{
}
//标识对应的分表对象的分表字段是创建时间时,自动创建时间
public interface IShardingKeyIsCreationTime
{
}

参考博客中的分表是基于Id做的,那我就试一下基于时间做分表。
正常来说新增实体的话只需要写一个ToDoItem 类就可以了,但参考博客中还定义了两个空接口,那么这两个空接口的作用是什么呢?

从这段代码中我们可以看出,这两个空接口可以帮你自动创建分表字段的值。

其实参考博客中也注释了这两个接口的作用:

我在我的实体代码中修改了这个注释,不知道我的理解对不对。

创建DbContext抽象类

参考博客中使用的是AbstractShardingAbpDbContext这个类,它是继承于AbpDbContext的。

但我的ABP的DbContext是继承于AbpZeroDbContext的。于是我找到了ShardingDbContext抽象类的源码

将AbstractShardingAbpZeroDbContext添加到我的项目中后,并继承AbstractShardingAbpZeroDbContext:

public class MyABP7NET6DbContext : AbstractShardingAbpZeroDbContext<Tenant, Role, User, MyABP7NET6DbContext>
{
    /* Define a DbSet for each entity of the application */
    public virtual DbSet<ToDoItem> ToDoItems { get; set; }

    public MyABP7NET6DbContext(DbContextOptions<MyABP7NET6DbContext> options)
        : base(options)
    {
    }
}

创建分表路由

public class TodoTableRoute : AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<ToDoItem>
{
    //分表的开始时间
    public override DateTime GetBeginTime()
    {
        return new DateTime(2022, 10, 1);
    }

    //注意一定要配置或者采用接口+标签也是可以的
    public override void Configure(EntityMetadataTableBuilder<ToDoItem> builder)
    {
        //创建时间按月分表
        builder.ShardingProperty(o => o.CreationTime);
    }

    public override bool AutoCreateTableByTime()
    {
        return true;
    }
}

startup配置

这里我把数据库连接字符串改成了获取配置文件的。
            // 添加分片配置
            services.AddShardingDbContext<MyABP7NET6DbContext>()
                .UseRouteConfig(op =>
                {
                    op.AddShardingTableRoute<TodoTableRoute>();
                }).UseConfig((sp, op) =>
                {
                    op.UseShardingQuery((conn, builder) =>
                    {
                        builder.UseSqlServer(conn);
                    });
                    op.UseShardingTransaction((conn, builder) =>
                    {
                        builder.UseSqlServer(conn);
                    });
                    op.AddDefaultDataSource(
                        Guid.NewGuid().ToString("n"),
                        _appConfiguration["ConnectionStrings:Default"]//"Data Source=localhost;Initial Catalog=EFCoreShardingTableDB;Integrated Security=True;"
                    );
                }).AddShardingCore();
            // sharding-core
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            // not required, enable check table missing and auto create,非必须  启动检查缺少的表并且创建
            app.ApplicationServices.UseAutoTryCompensateTable();

创建Controller

需要注入DbContext

[Route("api/[controller]/[action]")]
public class ToDoItemController : MyABP7NET6ControllerBase
{
    private readonly MyABP7NET6DbContext _dbContext;

    public ToDoItemController(
        MyABP7NET6DbContext dbContext
        )
    {
        _dbContext = dbContext;
    }

    [HttpPost]
    public async Task Add()
    {
        var msg = "测试数据";
        var currentTime = DateTime.Now;

        var list = await _dbContext.Set<ToDoItem>().ToListAsync();//如果数据中含有不符合路由条件的数据,会报错
        Console.WriteLine($"新增前数量:{list.Count}");

        await _dbContext.Set<ToDoItem>().AddAsync(new ToDoItem()
        {
            CreationTime = currentTime,
            Text = msg
        });

        await _dbContext.SaveChangesAsync();
        list = await _dbContext.Set<ToDoItem>().ToListAsync();
        Console.WriteLine($"新增后数量:{list.Count}");
    }

    [HttpPost]
    public async Task UpdateBatch()
    {
        _dbContext.Set<ToDoItem>().AsQueryable().ExecuteUpdate(update => update.SetProperty(x => x.CreationTime, x => x.CreationTime.AddYears(-10)));
    }
}

创建数据库迁移

PM> Add-Migration Add_ToDoItem
PM> update-database

因为在分表路由中配置了开始分表时间是2022-10-01,我现在是11月,所以框架自动创建了10月和11月两个表。

测试

调用Add和UpdateBatch接口

可以发现数据按照CreationTime自动分表了。
需要注意的是,使用EF CORE 7 的 ExecuteUpdate如果不写时间条件的话,会更新所有分表。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ABP框架中,实现租户功能需要以下步骤: 1. 定义租户实体 在应用程序中定义一个租户实体,用于保存租户的信息。可以在实体中定义一些用于多租户的属性,例如数据库连接字符串、数据库架构名称等。 2. 实现租户存储库 创建一个租户存储库,用于对租户实体进行CRUD操作。在存储库中,可以使用ABP框架提供的标准CRUD方法,例如GetAsync、InsertAsync、UpdateAsync等。 3. 实现租户管理器 创建一个租户管理器,用于获取当前租户的信息。在管理器中,可以使用ABP框架提供的多租户上下文对象(MultiTenancyContext)来获取当前租户的ID和名称等信息。 4. 实现租户过滤器 创建一个租户过滤器,用于在数据访问时自动为当前租户添加过滤条件。在过滤器中,可以使用ABP框架提供的多租户上下文对象来获取当前租户的数据库架构名称等信息,然后在执行SQL查询时添加过滤条件。 5. 配置ABP框架 最后,在ABP框架的配置文件中配置多租户相关的选项,例如租户管理器、租户过滤器等。可以使用ABP框架提供的依赖注入功能自动注入租户管理器和租户过滤器。 通过以上步骤,我们就可以实现租户功能,并且保证租户之间的数据隔离和安全性。需要注意的是,在实现多租户功能时,要合理使用租户ID、租户名称和数据库连接字符串等信息,以保证租户数据的正确性和安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值