using System; using System.Collections.Concurrent; using MySqlConnector; using ShardingCore.Core.EntityMetadatas; using ShardingCore.Core.VirtualDatabase.VirtualDataSources; using ShardingCore.Core.VirtualRoutes; using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine; using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions; 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 const string CurrentTableName = nameof(OrderByHour); private readonly IVirtualDataSource _virtualDataSource; private readonly IShardingTableCreator _shardingTableCreator; private readonly ConcurrentDictionary _tails = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private readonly object _lock = new object(); public OrderByHourRoute(IVirtualDataSource virtualDataSource, IShardingTableCreator shardingTableCreator) { _virtualDataSource = virtualDataSource; _shardingTableCreator = shardingTableCreator; InitTails(); } private void InitTails() { //启动寻找有哪些表后缀 using (var connection = new MySqlConnection(_virtualDataSource.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(CurrentTableName, StringComparison.OrdinalIgnoreCase)) { //如果没有下划线那么需要CurrentTableName.Length有下划线就要CurrentTableName.Length+1 _tails.TryAdd(tableName.Substring(CurrentTableName.Length+1),null); } } } } } } public override string ShardingKeyToTail(object shardingKey) { var dateTime = (DateTime)shardingKey; return ShardingKeyFormat(dateTime); } private string ShardingKeyFormat(DateTime dateTime) { var tail = $"{dateTime:yyyyMMddHH}"; return tail; } /// /// 如果你是非mysql数据库请自行实现这个方法返回当前类在数据库已经存在的后缀 /// 仅启动时调用 /// /// public override List GetTails() { return _tails.Keys.ToList(); } public override void Configure(EntityMetadataTableBuilder builder) { builder.ShardingProperty(o => o.CreateTime); } public override Func 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 TableRouteUnit RouteWithValue(DataSourceRouteResult dataSourceRouteResult, object shardingKey) { var shardingKeyToTail = ShardingKeyToTail(shardingKey); if (!_tails.TryGetValue(shardingKeyToTail, out var _)) { lock (_lock) { if (!_tails.TryGetValue(shardingKeyToTail, out var _)) { try { _shardingTableCreator.CreateTable(_virtualDataSource.DefaultDataSourceName, shardingKeyToTail); } catch (Exception ex) { Console.WriteLine("尝试添加表失败" + ex); } _tails.TryAdd(shardingKeyToTail, null); } } } return base.RouteWithValue(dataSourceRouteResult, shardingKey); } } }