private static List <string> BuildShardingCmds(MigrationOperation operation, string sourceCmd, ISqlGenerationHelper sqlGenerationHelper)
        {
            //所有MigrationOperation定义
            //https://github.com/dotnet/efcore/tree/b970bf29a46521f40862a01db9e276e6448d3cb0/src/EFCore.Relational/Migrations/Operations
            //ColumnOperation仅替换Table
            //其余其余都是将Name和Table使用分表名替换
            Dictionary <string, List <string> > _existsShardingTables
                = Cache.ServiceProvider.GetService <ShardingContainer>().ExistsShardingTables;

            List <string> resList      = new List <string>();
            string        absTableName = string.Empty;

            string name      = operation.GetPropertyValue("Name") as string;
            string tableName = operation.GetPropertyValue("Table") as string;
            string pattern   = string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName);

            Func <KeyValuePair <string, List <string> >, bool> where = x =>
                                                                       _existsShardingTables.Any(x => Regex.IsMatch(name, BuildPattern(x.Key)));

            if (!tableName.IsNullOrEmpty())
            {
                absTableName = tableName;
            }
            else if (!name.IsNullOrEmpty() && _existsShardingTables.Any(x => where (x)))
            {
                absTableName = _existsShardingTables.Where(x => where (x)).FirstOrDefault().Key;
            }

            //分表
            if (!absTableName.IsNullOrEmpty() && _existsShardingTables.ContainsKey(absTableName))
            {
                var shardings = _existsShardingTables[absTableName];
                shardings.ForEach(aShardingTable =>
                {
                    string newCmd = sourceCmd;
                    GetReplaceGroups(operation, absTableName, aShardingTable).ForEach(aReplace =>
                    {
                        newCmd = newCmd.Replace(
                            sqlGenerationHelper.DelimitIdentifier(aReplace.sourceName),
                            sqlGenerationHelper.DelimitIdentifier(aReplace.targetName));
                    });
                    resList.Add(newCmd);
                });
            }

            return(resList);

            string BuildPattern(string absTableName)
            {
                return(string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName));
            }
        }
        private void ReplaceName(MigrationOperation theOperation, string sourceName, string targetName)
        {
            string name      = theOperation.GetPropertyValue("Name") as string;
            string tableName = theOperation.GetPropertyValue("Table") as string;

            if (!tableName.IsNullOrEmpty())
            {
                theOperation.SetPropertyValue("Table", targetName);
            }
            if (!name.IsNullOrEmpty() && !(theOperation is ColumnOperation))
            {
                string[] patterns = new string[] { $"^()({sourceName})()$", $"^()({sourceName})(_.*?)$", $"^(.*?_)({sourceName})(_.*?)$", $"^(.*?_)({sourceName})()$" };
                foreach (var aPattern in patterns)
                {
                    if (Regex.IsMatch(name, aPattern))
                    {
                        var newName = new Regex(aPattern).Replace(name, "${1}" + targetName + "$3");
                        theOperation.SetPropertyValue("Name", newName);
                        break;
                    }
                }
            }
            Func <PropertyInfo, bool> propertyWhere = x =>
                                                      x.PropertyType.IsGenericType &&
                                                      x.PropertyType.GetGenericTypeDefinition() == typeof(List <>) &&
                                                      typeof(MigrationOperation).IsAssignableFrom(x.PropertyType.GetGenericArguments()[0]);

            //其它
            theOperation.GetType().GetProperties()
            .Where(x => x.Name != "Name" &&
                   x.Name != "Table" &&
                   x.PropertyType != typeof(object) &&
                   (typeof(MigrationOperation).IsAssignableFrom(x.PropertyType) || propertyWhere(x))
                   )
            .ToList()
            .ForEach(aProperty =>
            {
                var propertyValue = aProperty.GetValue(theOperation);
                if (propertyValue is MigrationOperation propertyOperation)
                {
                    ReplaceName(propertyOperation, sourceName, targetName);
                }
                else if (propertyWhere(aProperty))
                {
                    foreach (var aValue in (IEnumerable)propertyValue)
                    {
                        ReplaceName((MigrationOperation)aValue, sourceName, targetName);
                    }
                }
            });
        }
        private List <MigrationOperation> BuildShardingOperation(MigrationOperation sourceOperation)
        {
            //所有MigrationOperation定义
            //https://github.com/dotnet/efcore/tree/b970bf29a46521f40862a01db9e276e6448d3cb0/src/EFCore.Relational/Migrations/Operations
            //ColumnOperation仅替换Table
            //其余其余都是将Name和Table使用分表名替换

            List <MigrationOperation> resList = new List <MigrationOperation>();
            string absTableName = string.Empty;

            string name      = sourceOperation.GetPropertyValue("Name") as string;
            string tableName = sourceOperation.GetPropertyValue("Table") as string;
            string pattern   = string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName);

            Func <KeyValuePair <string, List <string> >, bool> where = x =>
                                                                       _existsShardingTables.Any(x => Regex.IsMatch(name, BuildPattern(x.Key)));

            if (!tableName.IsNullOrEmpty())
            {
                absTableName = tableName;
            }
            else if (!name.IsNullOrEmpty() && _existsShardingTables.Any(x => where (x)))
            {
                absTableName = _existsShardingTables.Where(x => where (x)).FirstOrDefault().Key;
            }

            //分表
            if (!absTableName.IsNullOrEmpty() && _existsShardingTables.ContainsKey(absTableName))
            {
                var shardings = _existsShardingTables[absTableName];
                shardings.ForEach(aSharding =>
                {
                    var clone = sourceOperation.DeepClone();
                    resList.Add(clone);
                    ReplaceName(clone, absTableName, aSharding);
                });
            }
            //不分表
            else
            {
                resList.Add(sourceOperation);
            }

            return(resList);

            string BuildPattern(string absTableName)
            {
                return(string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName));
            }
        }
        private static List <(string sourceName, string targetName)> GetReplaceGroups(
            MigrationOperation operation, string sourceTableName, string targetTableName)
        {
            List <(string sourceName, string targetName)> resList =
                new List <(string sourceName, string targetName)>
            {
                (sourceTableName, targetTableName)
            };

            string name = operation.GetPropertyValue("Name") as string;

            if (!name.IsNullOrEmpty() && !(operation is ColumnOperation))
            {
                string[] patterns = new string[] { $"^()({sourceTableName})()$", $"^()({sourceTableName})(_.*?)$", $"^(.*?_)({sourceTableName})(_.*?)$", $"^(.*?_)({sourceTableName})()$" };
                foreach (var aPattern in patterns)
                {
                    if (Regex.IsMatch(name, aPattern))
                    {
                        var newName = new Regex(aPattern).Replace(name, "${1}" + targetTableName + "$3");
                        resList.Add((name, newName));
                        break;
                    }
                }
            }
            Func <PropertyInfo, bool> listPropertyWhere = x =>
                                                          x.PropertyType.IsGenericType &&
                                                          x.PropertyType.GetGenericTypeDefinition() == typeof(List <>) &&
                                                          typeof(MigrationOperation).IsAssignableFrom(x.PropertyType.GetGenericArguments()[0]);

            //其它
            operation.GetType().GetProperties()
            .Where(x => x.Name != "Name" &&
                   x.Name != "Table" &&
                   x.PropertyType != typeof(object) &&
                   (typeof(MigrationOperation).IsAssignableFrom(x.PropertyType) || listPropertyWhere(x))
                   )
            .ToList()
            .ForEach(aProperty =>
            {
                var propertyValue = aProperty.GetValue(operation);
                if (propertyValue is MigrationOperation propertyOperation)
                {
                    resList.AddRange(GetReplaceGroups(propertyOperation, sourceTableName, targetTableName));
                }
                else if (listPropertyWhere(aProperty))
                {
                    foreach (var aValue in (IEnumerable)propertyValue)
                    {
                        resList.AddRange(GetReplaceGroups((MigrationOperation)aValue, sourceTableName, targetTableName));
                    }
                }
            });

            return(resList);
        }
    }