EFCore分表实现

当我们 new一个上下文 DbContext 后, 每次执行CURD方式时 ,都会依次调用 OnConfiguring(), OnModelCreating()两个方法。

  • OnConfiguring() 我们将用来替换一些服务实现,以支持分表的工作
  • OnModelCreating() 我们将用来重新实现 实体与数据库表 的映射关系

每次调用 OnModelCreating()时,会判断实体与数据库表的映射关系有没有改变,如果改变则采用新的映射关系。

DbContextBase 是一个 DbContext的实现,, ShardingRuleDbContextBase的一个共有属性。
根据分表规则的不同,每次的映射关系也会不同。

 public class DynamicModelCacheKeyFactoryDesignTimeSupport : IModelCacheKeyFactory
 {
        public object Create(DbContext context, bool designTime)
            => context is DbContextBase dynamicContext
                ? (context.GetType(), dynamicContext.ShardingRule, designTime)
                : (object)context.GetType();

        public object Create(DbContext context)
            => Create(context, false);

 }

OnConfiguring() 替换接口实现

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 {
            base.OnConfiguring(optionsBuilder);
            //如果分页规则有 ,代表需要分页, 那么需要替换对应的服务实现
            if (!string.IsNullOrEmpty(this.ShardingRule))
            {
                optionsBuilder.ReplaceService();
            }
 }

在每次调用 OnModelCreating() 时,方法内部会调用实现 IModelCustomizerModelCustomizer.csCustomize()方法,我们可以将映射关系写在此方法内。

通过继承实现:
IShardingTypeFinder 是一个类型查找器,请自行实现。

public class ShardingModelCustomizer : ModelCustomizer
{

        public ShardingModelCustomizer(ModelCustomizerDependencies dependencies) : base(dependencies)
        {
        }

        public override void Customize(ModelBuilder modelBuilder, DbContext context)
        {
            base.Customize(modelBuilder, context);
            var dbContextBase = context as DbContextBase;
            var shardingTypeFinder = dbContextBase.ServiceProvider.GetService();
            //查找需要重新映射表名的类
            var shardingTypes = shardingTypeFinder.FindAll(true);

            if (shardingTypes != null && shardingTypes.Count() > 0)
            {

                if (context is DbContextBase contextBase)
                {
                    if (!string.IsNullOrEmpty(contextBase.ShardingRule))
                    {
                        foreach (var type in shardingTypes)
                        {
                            switch (contextBase.DbContextOptions.DatabaseType)
                            {
                                case DatabaseType.SqlServer:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");
                                    break;
                                case DatabaseType.Sqlite:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");
                                    break;
                                case DatabaseType.MySql:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}".ToMySQLName());
                                    break;
                                case DatabaseType.Oracle:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}".ToOracleName());
                                    break;
                                default:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");
                                    break;
                            }
                        }
                    }
                }

            }

        }

}

OnConfiguring() 替换接口实现

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  {
            base.OnConfiguring(optionsBuilder);
            //如果分页规则有 ,代表需要分页, 那么需要替换对应的服务实现
            if (!string.IsNullOrEmpty(this.ShardingRule))
            {
                optionsBuilder.ReplaceService().ReplaceService();
            }
  }

上文提到了 ShardingRule 这个属性的出现 , 如何给这个属性赋值呢?
有两种方式:

  • 构造函数传参
  • 通过接口获取

构造函数传参

 public string ShardingRule { get; set; }
 public DbContextBase(string shardingRule, DbContextOptions options) : base(options)
 {
            ShardingRule = shardingRule;
 }

通过接口获取

IShardingRule是实现规则名称的自定义接口,自行实现

 protected DbContextBase(DbContextOptions options, IServiceProvider serviceProvider)
          : base(options)
 {
            ShardingRule = (serviceProvider.GetService()).GetValue();
 }

这里只介绍构造函数传参使用方式

 DbContextOptionsBuilder optionsBuilder = new DbContextOptionsBuilder();
 optionsBuilder.UseSqlServer("connStr");
 var options =  optionsBuilder.Options;
 using (var dbContext = new DbContextBase("202209", options))
 {
        //TODO....

 }

这里需要注意的是,跨上下文使用事务必须使用同一个连接,所以 optionsBuilder.UseSqlServer(connection);这里的写法改变一下,使用同一连接

            DbContextOptionsBuilder optionsBuilder = new DbContextOptionsBuilder();
            IDbConnection connection = new SqlConnection("connStr");
            optionsBuilder.UseSqlServer(connection);
            var options =  optionsBuilder.Options;
            using (var dbContext = new DbContextBase("202209", options))
            {
                using (var  transaction =await dbContext.Database.BeginTransactionAsync())
                {
                    using (var dbContext2 = new DbContextBase("202210", options))
                    {

                        await dbContext2.Database.UseTransactionAsync(transaction);
                        //TODO....

                        transaction.Commit();
                    }
                }

            }

EFCore分表的实现大致全是这样,没有什么区别。可以参考一些开源的框架,对现有的系统进行适当的调整,毕竟别人写的并不一定适合你。希望这篇文章可以帮到你。

Original: https://www.cnblogs.com/queque/p/16730570.html
Author: 张缺缺
Title: EFCore分表实现



相关阅读

Title: 解决 net core 3.x 跨域问题

跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。

以下几种情况是造成跨域的原因:

1.

  1. 域名相同,端口不同
  2. 域名相同,协议不同(即,一个是 http,一个是 https)
  3. 访问其他网站时,一个是域名,一个是对应的 IP地址(PS:http://www.a.com——http://192.168.1.1)
  4. 主域名相同,子域名不同
  5. 两个完全不相同的域名

简单来说,只有域名,协议,端口都相同才能通信

解决 net core 3.x 跨域问题

凡是这两种报错都属于跨域,一般来说,前端解决跨域比较复杂,所以一般后端解决跨域,因为过程相对简单。

这里以一个 Net Core 3.x WebApi 的框架的实例来解决这个问题

一、首先 WebApi 需要配置相对应的代码

这是官方的方案:https://learn.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.1

首先在 core 3.x 的 Startup.cs 文件里有 ConfigureServices 方法将服务添加到容器,将跨域的配置添加即可

跨域有两种配置方法,一种是允许所有域名,一种是配置部分域名通信,配置方法略有不同参考代码如下:

1      public void ConfigureServices(IServiceCollection services)
 2         {
 3             #region 解决跨域
 4             //"Cors"表示策略名称,可以随便起;可以添加多条策略。
 5             //AllowAnyOrigin表示允许任何域;AllowAnyMethod表示允许任何方法;AllowAnyHeader表示允许任何消息头。
 6             //如果是允许指定的域、方法、消息头需要使用WithOrigins、WithMethods、WithHeaders方法。
 7             services.AddCors(options =>
 8             {
 9                 options.AddPolicy("Cors", builder =>
10                 {
11                     builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
12                 });
13             });
14
15             ////允许一个或多个来源可以跨域
16             //services.AddCors(options =>
17             //{
18             //    options.AddPolicy("CustomCors", policy =>
19             //    {
20             //        // 设定允许跨域的来源,有多个可以用','隔开
21             //        policy.WithOrigins("http://localhost:9000")
22             //        .AllowAnyHeader()
23             //        .AllowAnyMethod()
24             //        .AllowCredentials();
25             //    });
26             //});
27             #endregion
28
29             services.AddControllers();
30         }

在 ConfigureServices 配置后,只需要在 HTTP请求管道 中调用即可

添加一句代码即可,但是名称一定要与服务中定义的名称一致

添加时需要注意,对 UseCors 的调用必须放在 UseRouting 之后,但在 UseAuthorization 之前。

1      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 2         {
 3
 4
 5             if (env.IsDevelopment())
 6             {
 7                 app.UseDeveloperExceptionPage();
 8             }
 9
10             //添加日志中间件
11             app.UseLog();
12
13             //全局捕捉异常
14             app.UseExceptionMiddleware();
15
16             app.UseHttpsRedirection();
17             app.UseRouting();
18
19             //跨域
20             app.UseCors("Cors");
21             //app.UseCors("CustomCors");
22
23             //用户认证
24             app.UseAuthentication();
25             app.UseAuthorization();
26
27             // 添加Swagger有关中间件
28             app.UseSwagger();
29             app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "API Demo v1"); });
30
31             app.UseEndpoints(endpoints =>
32             {
33                 endpoints.MapControllers();
34             });
35         }

那么到这里,你是不是觉得已经配置完成,就可以使用 ajax 直接访问接口不会报错了。

我这里的做法时,将 WebApi 的代码发布到本地的 IIS 中进行测试的,但结果是,这样配置后,依然无法解决跨域的问题,后来查阅发现,这个配置只完成了一半。

二、IIS 服务器配置

如果是本地访问 WebApi 这种方式是没有问题的,发布线上这种方式就不可以了,所以还要完成 IIS 服务器的配置

1.

  1. 在 IIS 中添加一个创建一个自签名的证书
  2. 在新建 WebApi 网站时,选择 https 协议,配置创建的证书

解决 net core 3.x 跨域问题

完成这 3 个步骤,本地访问 IIS 发布的 WebApi 的接口,跨域问题即可解决

如果是发布的 Web 网站去放问发布的 WebApi ,同样的也需要对网站进行证书配置

至于在网上看到的其他方案,在 html 头部加 这段代码,,,,总之,我试了,线上不行但是加上也不会报错没影响

还有一种,在控制器加 [EnableCors(“{Policy String}”)] 这个中间件属性,这种是可以的,但是他是对部分接口或控制器进行跨域配置,如果你是全局就没必要加这个属性

本地跨域和线上跨域解决方式是有不同的,就是多了一个 IIS 配置而已,所以在解决这个问题时,要注意自己对应的是那种方式 (其实很简单的问题,因为没搞清楚方式,我解决这个问题花了半天时间)

总之,解决问题要找到点。而且这个问题后端解决很容易,就不要麻烦前端了,很多刚入行的新手,因为缺少经验以为前端能解决,就把问题丢给前端,实际上后端更容易解决这个问题。(个人观点,不代表所有,嘴下留情)

Original: https://www.cnblogs.com/liuchenxing/p/16868666.html
Author: object0812
Title: 解决 net core 3.x 跨域问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/364675/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

最近整理资源【免费获取】:   👉 程序员最新必读书单  | 👏 互联网各方向面试题下载 | ✌️计算机核心资源汇总