From 98f570cc4499302172658604d8d8577fe807ffc5 Mon Sep 17 00:00:00 2001 From: xuejmnet <326308290@qq.com> Date: Tue, 10 May 2022 21:21:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=A6=82=E6=9E=9C=E4=B8=8D?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E8=A1=A8=E5=B0=B1=E5=88=9B=E5=BB=BA=20[#147]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ShardingCore.sln | 7 + .../Controllers/WeatherForecastController.cs | 52 ++++ .../DefaultDbContext.cs | 29 ++ .../Sample.AutoCreateIfPresent/OrderByHour.cs | 17 ++ .../OrderByHourMap.cs | 23 ++ .../OrderByHourRoute.cs | 173 ++++++++++++ samples/Sample.AutoCreateIfPresent/Program.cs | 58 ++++ .../Properties/launchSettings.json | 31 +++ .../Sample.AutoCreateIfPresent.csproj | 18 ++ .../WeatherForecast.cs | 12 + .../appsettings.Development.json | 8 + .../appsettings.json | 9 + src/ShardingCore/IShardingConfigOption.cs | 103 ------- src/ShardingCore/ShardingConfigOption.cs | 259 ------------------ 14 files changed, 437 insertions(+), 362 deletions(-) create mode 100644 samples/Sample.AutoCreateIfPresent/Controllers/WeatherForecastController.cs create mode 100644 samples/Sample.AutoCreateIfPresent/DefaultDbContext.cs create mode 100644 samples/Sample.AutoCreateIfPresent/OrderByHour.cs create mode 100644 samples/Sample.AutoCreateIfPresent/OrderByHourMap.cs create mode 100644 samples/Sample.AutoCreateIfPresent/OrderByHourRoute.cs create mode 100644 samples/Sample.AutoCreateIfPresent/Program.cs create mode 100644 samples/Sample.AutoCreateIfPresent/Properties/launchSettings.json create mode 100644 samples/Sample.AutoCreateIfPresent/Sample.AutoCreateIfPresent.csproj create mode 100644 samples/Sample.AutoCreateIfPresent/WeatherForecast.cs create mode 100644 samples/Sample.AutoCreateIfPresent/appsettings.Development.json create mode 100644 samples/Sample.AutoCreateIfPresent/appsettings.json delete mode 100644 src/ShardingCore/IShardingConfigOption.cs delete mode 100644 src/ShardingCore/ShardingConfigOption.cs diff --git a/ShardingCore.sln b/ShardingCore.sln index 2044943c..aa3ac6bf 100644 --- a/ShardingCore.sln +++ b/ShardingCore.sln @@ -61,6 +61,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.NoShardingMultiLevel EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.MultiConfig", "samples\Sample.MultiConfig\Sample.MultiConfig.csproj", "{D839D632-4AE4-4F75-8A2C-49EE029B0787}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.AutoCreateIfPresent", "samples\Sample.AutoCreateIfPresent\Sample.AutoCreateIfPresent.csproj", "{40C83D48-0614-4651-98C6-2ABBE857D83D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -155,6 +157,10 @@ Global {D839D632-4AE4-4F75-8A2C-49EE029B0787}.Debug|Any CPU.Build.0 = Debug|Any CPU {D839D632-4AE4-4F75-8A2C-49EE029B0787}.Release|Any CPU.ActiveCfg = Release|Any CPU {D839D632-4AE4-4F75-8A2C-49EE029B0787}.Release|Any CPU.Build.0 = Release|Any CPU + {40C83D48-0614-4651-98C6-2ABBE857D83D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40C83D48-0614-4651-98C6-2ABBE857D83D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40C83D48-0614-4651-98C6-2ABBE857D83D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40C83D48-0614-4651-98C6-2ABBE857D83D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -182,6 +188,7 @@ Global {ED191305-AB19-4863-A48A-7BA4C21F467B} = {B458D737-33C5-4C10-9687-0BED2E7CD346} {DCEBAC86-E62B-4B6C-A352-B8C1C2C6F734} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} {D839D632-4AE4-4F75-8A2C-49EE029B0787} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} + {40C83D48-0614-4651-98C6-2ABBE857D83D} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8C07A667-E8B4-43C7-8053-721584BAD291} diff --git a/samples/Sample.AutoCreateIfPresent/Controllers/WeatherForecastController.cs b/samples/Sample.AutoCreateIfPresent/Controllers/WeatherForecastController.cs new file mode 100644 index 00000000..124476c1 --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/Controllers/WeatherForecastController.cs @@ -0,0 +1,52 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Sample.AutoCreateIfPresent.Controllers; + +[ApiController] +[Route("[controller]/[action]")] +public class WeatherForecastController : ControllerBase +{ + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + private readonly DefaultDbContext _defaultDbContext; + + public WeatherForecastController(ILogger logger,DefaultDbContext defaultDbContext) + { + _logger = logger; + _defaultDbContext = defaultDbContext; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + + public async Task Query() + { + var list =await _defaultDbContext.Set().ToListAsync(); + return Ok(list); + } + public async Task Insert() + { + var orderByHour = new OrderByHour(); + orderByHour.Id = Guid.NewGuid().ToString("n"); + orderByHour.Name=$"Name:"+ Guid.NewGuid().ToString("n"); + var dateTime = DateTime.Now; + orderByHour.CreateTime = dateTime.AddHours(new Random().Next(1, 20)); + await _defaultDbContext.AddAsync(orderByHour); + await _defaultDbContext.SaveChangesAsync(); + return Ok(); + } +} \ No newline at end of file diff --git a/samples/Sample.AutoCreateIfPresent/DefaultDbContext.cs b/samples/Sample.AutoCreateIfPresent/DefaultDbContext.cs new file mode 100644 index 00000000..4e119cd2 --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/DefaultDbContext.cs @@ -0,0 +1,29 @@ +using System; +using Microsoft.EntityFrameworkCore; +using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions; +using ShardingCore.Sharding; +using ShardingCore.Sharding.Abstractions; + +/* +* @Author: xjm +* @Description: +* @Date: DATE +* @Email: 326308290@qq.com +*/ +namespace Sample.AutoCreateIfPresent +{ + public class DefaultDbContext:AbstractShardingDbContext,IShardingTableDbContext + { + public DefaultDbContext(DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.ApplyConfiguration(new OrderByHourMap()); + } + + public IRouteTail RouteTail { get; set; } + } +} \ No newline at end of file diff --git a/samples/Sample.AutoCreateIfPresent/OrderByHour.cs b/samples/Sample.AutoCreateIfPresent/OrderByHour.cs new file mode 100644 index 00000000..d7517a4d --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/OrderByHour.cs @@ -0,0 +1,17 @@ +using System; + +/* +* @Author: xjm +* @Description: +* @Date: DATE +* @Email: 326308290@qq.com +*/ +namespace Sample.AutoCreateIfPresent +{ + public class OrderByHour + { + public string Id { get; set; } + public DateTime CreateTime { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/samples/Sample.AutoCreateIfPresent/OrderByHourMap.cs b/samples/Sample.AutoCreateIfPresent/OrderByHourMap.cs new file mode 100644 index 00000000..bd015184 --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/OrderByHourMap.cs @@ -0,0 +1,23 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +/* +* @Author: xjm +* @Description: +* @Date: DATE +* @Email: 326308290@qq.com +*/ +namespace Sample.AutoCreateIfPresent +{ + public class OrderByHourMap:IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(o => o.Id); + builder.Property(o => o.Id).IsRequired().HasMaxLength(50); + builder.Property(o => o.Name).IsRequired().HasMaxLength(128); + builder.ToTable(nameof(OrderByHour)); + } + } +} \ No newline at end of file diff --git a/samples/Sample.AutoCreateIfPresent/OrderByHourRoute.cs b/samples/Sample.AutoCreateIfPresent/OrderByHourRoute.cs new file mode 100644 index 00000000..415ff7dc --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/OrderByHourRoute.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Concurrent; +using System.Linq.Expressions; +using MySqlConnector; +using ShardingCore; +using ShardingCore.Core.EntityMetadatas; +using ShardingCore.Core.PhysicTables; +using ShardingCore.Core.ShardingConfigurations; +using ShardingCore.Core.ShardingConfigurations.Abstractions; +using ShardingCore.Core.VirtualDatabase.VirtualDataSources.Abstractions; +using ShardingCore.Core.VirtualDatabase.VirtualTables; +using ShardingCore.Core.VirtualRoutes; +using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions; +using ShardingCore.Exceptions; +using ShardingCore.Extensions; +using ShardingCore.TableCreator; + +/* +* @Author: xjm +* @Description: +* @Date: DATE +* @Email: 326308290@qq.com +*/ +namespace Sample.AutoCreateIfPresent +{ + public class OrderByHourRoute : AbstractShardingOperatorVirtualTableRoute + { + private const string Tables = "Tables"; + private const string TABLE_SCHEMA = "TABLE_SCHEMA"; + private const string TABLE_NAME = "TABLE_NAME"; + private readonly IVirtualDataSourceManager _virtualDataSourceManager; + private readonly IVirtualTableManager _virtualTableManager; + private readonly IShardingTableCreator _shardingTableCreator; + private readonly ConcurrentDictionary _tails = new ConcurrentDictionary(); + private readonly object _lock = new object(); + + public OrderByHourRoute(IVirtualDataSourceManager virtualDataSourceManager,IVirtualTableManager virtualTableManager, IShardingTableCreator shardingTableCreator) + { + _virtualDataSourceManager = virtualDataSourceManager; + _virtualTableManager = virtualTableManager; + _shardingTableCreator = shardingTableCreator; + } + + private string ShardingKeyFormat(DateTime dateTime) + { + var tail = $"{dateTime:yyyyMMddHH}"; + + return tail; + } + + public override string ShardingKeyToTail(object shardingKey) + { + var dateTime = (DateTime)shardingKey; + return ShardingKeyFormat(dateTime); + } + + public override List GetAllTails() + { + //启动寻找有哪些表后缀 + using (var connection = new MySqlConnection(_virtualDataSourceManager.GetCurrentVirtualDataSource().DefaultConnectionString)) + { + connection.Open(); + var database = connection.Database; + + using (var dataTable = connection.GetSchema(Tables)) + { + for (int i = 0; i < dataTable.Rows.Count; i++) + { + var schema = dataTable.Rows[i][TABLE_SCHEMA]; + if (database.Equals($"{schema}", StringComparison.OrdinalIgnoreCase)) + { + var tableName = dataTable.Rows[i][TABLE_NAME]?.ToString()??string.Empty; + if (tableName.StartsWith(nameof(OrderByHour))) + { + _tails.TryAdd(tableName.Replace($"{nameof(OrderByHour)}_",""),null); + } + } + } + } + } + return _tails.Keys.ToList(); + } + + public override void Configure(EntityMetadataTableBuilder builder) + { + builder.ShardingProperty(o => o.CreateTime); + } + + public override Expression> GetRouteToFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator) + { + var t = ShardingKeyFormat(shardingKey); + switch (shardingOperator) + { + case ShardingOperatorEnum.GreaterThan: + case ShardingOperatorEnum.GreaterThanOrEqual: + return tail => String.Compare(tail, t, StringComparison.Ordinal) >= 0; + case ShardingOperatorEnum.LessThan: + { + var currentHourBeginTime = new DateTime(shardingKey.Year,shardingKey.Month,shardingKey.Day,shardingKey.Hour,0,0); + //处于临界值 o=>o.time < [2021-01-01 00:00:00] 尾巴20210101不应该被返回 + if (currentHourBeginTime == shardingKey) + return tail => String.Compare(tail, t, StringComparison.Ordinal) < 0; + return tail => String.Compare(tail, t, StringComparison.Ordinal) <= 0; + } + case ShardingOperatorEnum.LessThanOrEqual: + return tail => String.Compare(tail, t, StringComparison.Ordinal) <= 0; + case ShardingOperatorEnum.Equal: return tail => tail == t; + default: + { +#if DEBUG + Console.WriteLine($"shardingOperator is not equal scan all table tail"); +#endif + return tail => true; + } + } + } + + public override IPhysicTable RouteWithValue(List allPhysicTables, object shardingKey) + { + var shardingKeyToTail = ShardingKeyToTail(shardingKey); + + if (!_tails.TryGetValue(shardingKeyToTail,out var _)) + { + lock (_lock) + { + if (!_tails.TryGetValue(shardingKeyToTail,out var _)) + { + var virtualTable = _virtualTableManager.GetVirtualTable(typeof(OrderByHour)); + _virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, shardingKeyToTail)); + try + { + _shardingTableCreator.CreateTable(_virtualDataSourceManager.GetCurrentVirtualDataSource().DefaultDataSourceName, shardingKeyToTail); + } + catch (Exception ex) + { + Console.WriteLine("尝试添加表失败" + ex); + } + + _tails.TryAdd(shardingKeyToTail,null); + } + } + } + + var needRefresh = allPhysicTables.Count != _tails.Count; + if (needRefresh) + { + var virtualTable = _virtualTableManager.GetVirtualTable(typeof(OrderByHour)); + foreach (var tail in _tails.Keys) + { + var hashSet = allPhysicTables.Select(o=>o.Tail).ToHashSet(); + if (!hashSet.Contains(tail)) + { + var tables = virtualTable.GetAllPhysicTables(); + var physicTable = tables.FirstOrDefault(o=>o.Tail==tail); + if (physicTable!= null) + { + allPhysicTables.Add(physicTable); + } + } + } + } + var physicTables = allPhysicTables.Where(o => o.Tail== shardingKeyToTail).ToList(); + if (physicTables.IsEmpty()) + { + throw new ShardingCoreException($"sharding key route not match {EntityMetadata.EntityType} -> [{EntityMetadata.ShardingTableProperty.Name}] ->【{shardingKey}】 all tails ->[{string.Join(",", allPhysicTables.Select(o=>o.FullName))}]"); + } + + if (physicTables.Count > 1) + throw new ShardingCoreException($"more than one route match table:{string.Join(",", physicTables.Select(o => $"[{o.FullName}]"))}"); + return physicTables[0]; + } + } +} \ No newline at end of file diff --git a/samples/Sample.AutoCreateIfPresent/Program.cs b/samples/Sample.AutoCreateIfPresent/Program.cs new file mode 100644 index 00000000..e6f62a3a --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/Program.cs @@ -0,0 +1,58 @@ +using Microsoft.EntityFrameworkCore; +using Sample.AutoCreateIfPresent; +using ShardingCore; +using ShardingCore.Bootstrapers; +using ShardingCore.Core.VirtualDatabase.VirtualTables; +using ShardingCore.TableExists; + +ILoggerFactory efLogger = LoggerFactory.Create(builder => +{ + builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole(); +}); + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +builder.Services.AddShardingDbContext() + .AddEntityConfig(o => + { + o.CreateShardingTableOnStart = true; + o.EnsureCreatedWithOutShardingTable = true; + o.AddShardingTableRoute(); + }) + .AddConfig(o => + { + o.ConfigId = "c1"; + o.AddDefaultDataSource("ds0", "server=127.0.0.1;port=3306;database=shardingTest;userid=root;password=root;"); + o.UseShardingQuery((conn, b) => + { + b.UseMySql(conn, new MySqlServerVersion(new Version())).UseLoggerFactory(efLogger); + }); + o.UseShardingTransaction((conn, b) => + { + b.UseMySql(conn, new MySqlServerVersion(new Version())).UseLoggerFactory(efLogger); + }); + o.ReplaceTableEnsureManager(sp=>new MySqlTableEnsureManager()); + }).EnsureConfig(); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} +app.Services.GetRequiredService().Start(); + + + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); \ No newline at end of file diff --git a/samples/Sample.AutoCreateIfPresent/Properties/launchSettings.json b/samples/Sample.AutoCreateIfPresent/Properties/launchSettings.json new file mode 100644 index 00000000..8ceb2416 --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:26918", + "sslPort": 44347 + } + }, + "profiles": { + "Sample.AutoCreateIfPresent": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7066;http://localhost:5218", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/samples/Sample.AutoCreateIfPresent/Sample.AutoCreateIfPresent.csproj b/samples/Sample.AutoCreateIfPresent/Sample.AutoCreateIfPresent.csproj new file mode 100644 index 00000000..67bde0f2 --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/Sample.AutoCreateIfPresent.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/samples/Sample.AutoCreateIfPresent/WeatherForecast.cs b/samples/Sample.AutoCreateIfPresent/WeatherForecast.cs new file mode 100644 index 00000000..b823652e --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/WeatherForecast.cs @@ -0,0 +1,12 @@ +namespace Sample.AutoCreateIfPresent; + +public class WeatherForecast +{ + public DateTime Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } +} \ No newline at end of file diff --git a/samples/Sample.AutoCreateIfPresent/appsettings.Development.json b/samples/Sample.AutoCreateIfPresent/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/samples/Sample.AutoCreateIfPresent/appsettings.json b/samples/Sample.AutoCreateIfPresent/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/samples/Sample.AutoCreateIfPresent/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/ShardingCore/IShardingConfigOption.cs b/src/ShardingCore/IShardingConfigOption.cs deleted file mode 100644 index c93b89bf..00000000 --- a/src/ShardingCore/IShardingConfigOption.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.EntityFrameworkCore; -using ShardingCore.Core; -using ShardingCore.Core.VirtualRoutes.TableRoutes; -using ShardingCore.Sharding.Abstractions; -using ShardingCore.Sharding.ParallelTables; - -namespace ShardingCore -{ - /* - * @Author: xjm - * @Description: - * @Date: 2021/8/20 6:56:49 - * @Ver: 1.0 - * @Email: 326308290@qq.com - */ - public interface IShardingConfigOption - { - bool UseReadWrite { get; } - - bool HasVirtualTableRoute(Type entityType); - Type GetVirtualTableRouteType(Type entityType); - bool HasVirtualDataSourceRoute(Type entityType); - Type GetVirtualDataSourceRouteType(Type entityType); - - ISet GetShardingTableRouteTypes(); - ISet GetShardingDataSourceRouteTypes(); - - - IDictionary GetDataSources(); - - - /// - /// 如果数据库不存在就创建并且创建表除了分表的 - /// - public bool EnsureCreatedWithOutShardingTable { get; set; } - /// - /// 是否需要在启动时创建分表 - /// - public bool? CreateShardingTableOnStart { get; set; } - /// - /// 添加尝试建表的对象 - /// - /// - /// - public bool AddEntityTryCreateTable(Type entityType); - public bool AnyEntityTryCreateTable(); - /// - /// 是否需要启动创建表 - /// - /// - /// - public bool NeedCreateTable(Type entityType); - /// - /// 忽略建表时的错误 - /// - public bool? IgnoreCreateTableError { get; set; } - - ///// - ///// 自动追踪实体 - ///// - //public bool AutoTrackEntity { get; set; } - /// - /// 默认数据源名称 - /// - public string DefaultDataSourceName { get; set; } - /// - /// 默认数据库链接字符串 - /// - public string DefaultConnectionString { get; set; } - /// - /// 最大查询连接数限制 - /// - public int MaxQueryConnectionsLimit { get; set; } - /// - /// 连接数限制 - /// - public ConnectionModeEnum ConnectionMode { get; set; } - /// - /// 当查询遇到没有路由被命中时是否抛出错误 - /// - public bool ThrowIfQueryRouteNotMatch { get; set; } - - public bool AddParallelTableGroupNode(ParallelTableGroupNode parallelTableGroupNode); - - public ISet GetParallelTableGroupNodes(); - /// - /// 是否启用表路由编译缓存 - /// - public bool? EnableTableRouteCompileCache { get; set; } - /// - /// 是否启用分库路由编译缓存 - /// - public bool? EnableDataSourceRouteCompileCache { get; set; } - } - - public interface IShardingConfigOption: IShardingConfigOption where TShardingDbContext : DbContext, IShardingDbContext - { - - } -} diff --git a/src/ShardingCore/ShardingConfigOption.cs b/src/ShardingCore/ShardingConfigOption.cs deleted file mode 100644 index be6d5843..00000000 --- a/src/ShardingCore/ShardingConfigOption.cs +++ /dev/null @@ -1,259 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ShardingCore.Core.VirtualRoutes.TableRoutes; -using ShardingCore.Sharding.Abstractions; -using ShardingCore.Sharding.ReadWriteConfigurations; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Data.Common; -using System.Linq; -using ShardingCore.Core; -using ShardingCore.Core.VirtualRoutes.DataSourceRoutes; -using ShardingCore.Exceptions; -using ShardingCore.Extensions; -using ShardingCore.Sharding.ParallelTables; -using ShardingCore.Sharding.ShardingComparision; -using ShardingCore.Sharding.ShardingComparision.Abstractions; -using ShardingCore.TableExists; -using ShardingCore.TableExists.Abstractions; - -namespace ShardingCore -{ - /* - * @Author: xjm - * @Description: - * @Date: 2021/8/16 15:18:37 - * @Ver: 1.0 - * @Email: 326308290@qq.com - */ - public class ShardingConfigOption : IShardingConfigOption - where TShardingDbContext : DbContext, IShardingDbContext - { - private readonly Dictionary _virtualDataSourceRoutes = new Dictionary(); - private readonly Dictionary _virtualTableRoutes = new Dictionary(); - private readonly ISet _createTableEntities = new HashSet(); - public readonly ISet _parallelTables = new HashSet(); - - public Action SameConnectionConfigure { get; private set; } - - public Func> DataSourcesConfigure { get; private set; } - public void UseShardingTransaction(Action transactionConfigure) - { - SameConnectionConfigure = transactionConfigure ?? throw new ArgumentNullException(nameof(transactionConfigure)); - } - - public void AddShardingDataSource(Func> dataSourcesConfigure) - { - DataSourcesConfigure = dataSourcesConfigure ?? throw new ArgumentNullException(nameof(dataSourcesConfigure)); - } - - public Func ReplaceShardingComparerFactory { get; private set; } = sp => new CSharpLanguageShardingComparer(); - /// - /// 替换默认的比较器 - /// - /// - /// - public void ReplaceShardingComparer(Func newShardingComparerFactory) - { - ReplaceShardingComparerFactory=newShardingComparerFactory ?? throw new ArgumentNullException(nameof(newShardingComparerFactory)); - } - - public Func> TableEnsureManagerFactory { get; private set; } = sp => new EmptyTableEnsureManager< TShardingDbContext>(); - public void AddTableEnsureManager(Func> newTableEnsureManagerFactory) - { - TableEnsureManagerFactory= newTableEnsureManagerFactory?? throw new ArgumentNullException(nameof(newTableEnsureManagerFactory)); - } - - - ///// - ///// 配置数据库分表查询和保存时的DbContext创建方式 - ///// - ///// DbConnection下如何配置因为不同的DbContext支持事务需要使用同一个DbConnection - ///// 默认查询DbContext创建的配置 - - //public void UseShardingOptionsBuilder(Action sameConnectionConfigure, Action defaultQueryConfigure = null) - //{ - // ConnectionConfigure = sameConnectionConfigure ?? throw new ArgumentNullException(nameof(sameConnectionConfigure)); - // ConnectionStringConfigure = defaultQueryConfigure ?? throw new ArgumentNullException(nameof(defaultQueryConfigure)); - //} - - public bool UseReadWrite => ReadConnStringConfigure != null; - public Func>> ReadConnStringConfigure { get; private set; } - public ReadStrategyEnum ReadStrategyEnum { get; private set; } - public bool ReadWriteDefaultEnable { get; private set; } - public int ReadWriteDefaultPriority { get; private set; } - public ReadConnStringGetStrategyEnum ReadConnStringGetStrategy { get; private set; } - - /// - /// 使用读写分离配置 - /// - /// - /// - /// 考虑到很多时候读写分离的延迟需要马上用到写入的数据所以默认关闭需要的话自己开启或者通过IShardingReadWriteManager,false表示默认不走读写分离除非你自己开启,true表示默认走读写分离除非你禁用, - /// IShardingReadWriteManager.CreateScope()会判断dbcontext的priority然后判断是否启用readwrite - /// 读写分离可能会造成每次查询不一样甚至分表后的分页会有错位问题,因为他不是一个原子操作,所以如果整个请求为一次读写切换大多数更加合适 - public void UseReadWriteConfiguration(Func>> readConnStringConfigure, ReadStrategyEnum readStrategyEnum, bool defaultEnable = false, int defaultPriority = 10, ReadConnStringGetStrategyEnum readConnStringGetStrategy = ReadConnStringGetStrategyEnum.LatestFirstTime) - { - ReadConnStringConfigure = readConnStringConfigure ?? throw new ArgumentNullException(nameof(readConnStringConfigure)); - ReadStrategyEnum = readStrategyEnum; - ReadWriteDefaultEnable = defaultEnable; - ReadWriteDefaultPriority = defaultPriority; - ReadConnStringGetStrategy = readConnStringGetStrategy; - } - - /// - /// 添加分表路由 - /// - /// - public void AddShardingDataSourceRoute() where TRoute : IVirtualDataSourceRoute - { - var routeType = typeof(TRoute); - AddShardingDataSourceRoute(routeType); - } - public void AddShardingDataSourceRoute(Type routeType) - { - if (!routeType.IsVirtualDataSourceRoute()) - throw new ShardingCoreInvalidOperationException(routeType.FullName); - //获取类型 - var genericVirtualRoute = routeType.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IVirtualDataSourceRoute<>) - && it.GetGenericArguments().Any()); - if (genericVirtualRoute == null) - throw new ArgumentException("add sharding route type error not assignable from IVirtualDataSourceRoute<>."); - - var shardingEntityType = genericVirtualRoute.GetGenericArguments()[0]; - if (shardingEntityType == null) - throw new ArgumentException("add sharding table route type error not assignable from IVirtualDataSourceRoute<>"); - if (!_virtualDataSourceRoutes.ContainsKey(shardingEntityType)) - { - _virtualDataSourceRoutes.Add(shardingEntityType, routeType); - } - } - /// - /// 添加分表路由 - /// - /// - public void AddShardingTableRoute() where TRoute : IVirtualTableRoute - { - var routeType = typeof(TRoute); - AddShardingTableRoute(routeType); - } - public void AddShardingTableRoute(Type routeType) - { - if (!routeType.IsIVirtualTableRoute()) - throw new ShardingCoreInvalidOperationException(routeType.FullName); - //获取类型 - var genericVirtualRoute = routeType.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IVirtualTableRoute<>) - && it.GetGenericArguments().Any()); - if (genericVirtualRoute == null) - throw new ArgumentException("add sharding route type error not assignable from IVirtualTableRoute<>."); - - var shardingEntityType = genericVirtualRoute.GetGenericArguments()[0]; - if (shardingEntityType == null) - throw new ArgumentException("add sharding table route type error not assignable from IVirtualTableRoute<>"); - if (!_virtualTableRoutes.ContainsKey(shardingEntityType)) - { - _virtualTableRoutes.Add(shardingEntityType, routeType); - } - } - - public bool HasVirtualTableRoute(Type entityType) - { - return _virtualTableRoutes.ContainsKey(entityType); - } - - public Type GetVirtualTableRouteType(Type entityType) - { - if (!_virtualTableRoutes.ContainsKey(entityType)) - throw new ArgumentException($"{entityType} not found IVirtualTableRoute"); - return _virtualTableRoutes[entityType]; - } - - public bool HasVirtualDataSourceRoute(Type entityType) - { - return _virtualDataSourceRoutes.ContainsKey(entityType); - } - - public Type GetVirtualDataSourceRouteType(Type entityType) - { - if (!_virtualDataSourceRoutes.ContainsKey(entityType)) - throw new ArgumentException($"{entityType} not found IVirtualDataSourceRoute"); - return _virtualDataSourceRoutes[entityType]; - } - - public ISet GetShardingTableRouteTypes() - { - return _virtualTableRoutes.Keys.ToHashSet(); - } - - public ISet GetShardingDataSourceRouteTypes() - { - return _virtualDataSourceRoutes.Keys.ToHashSet(); - } - - public IDictionary GetDataSources() - { - var defaultDataSources = new Dictionary(){{DefaultDataSourceName,DefaultConnectionString}}; - return defaultDataSources.Concat(DataSourcesConfigure?.Invoke(ShardingContainer.ServiceProvider)??new Dictionary()).ToDictionary(o=>o.Key,o=>o.Value); - } - - - /// - /// 如果数据库不存在就创建并且创建表除了分表的 - /// - public bool EnsureCreatedWithOutShardingTable { get; set; } - - /// - /// 是否需要在启动时创建分表 - /// - public bool? CreateShardingTableOnStart { get; set; } - - public bool AddEntityTryCreateTable(Type entityType) - { - return _createTableEntities.Add(entityType); - } - - public bool AnyEntityTryCreateTable() - { - return _createTableEntities.Any(); - } - - public bool NeedCreateTable(Type entityType) - { - return _createTableEntities.Contains(entityType); - } - - /// - /// 忽略建表时的错误 - /// - public bool? IgnoreCreateTableError { get; set; } = true; - ///// - ///// 自动追踪实体 - ///// - //public bool AutoTrackEntity { get; set; } - - public string DefaultDataSourceName { get; set; } - public string DefaultConnectionString { get; set; } - public int MaxQueryConnectionsLimit { get; set; } = Environment.ProcessorCount; - public ConnectionModeEnum ConnectionMode { get; set; } = ConnectionModeEnum.SYSTEM_AUTO; - /// - /// 当查询遇到没有路由被命中时是否抛出错误 - /// - public bool ThrowIfQueryRouteNotMatch { get; set; } = true; - public bool? EnableTableRouteCompileCache { get; set; } - public bool? EnableDataSourceRouteCompileCache { get; set; } - - - public bool AddParallelTableGroupNode(ParallelTableGroupNode parallelTableGroupNode) - { - Check.NotNull(parallelTableGroupNode, $"{nameof(parallelTableGroupNode)}"); - return _parallelTables.Add(parallelTableGroupNode); - } - public ISet GetParallelTableGroupNodes() - { - return _parallelTables; - } - //public bool? EnableTableRouteCompileCache { get; set; } - //public bool? EnableDataSourceRouteCompileCache { get; set; } - - } -} \ No newline at end of file