// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! namespace Admin.NET.Core.Service; public static class BuildSQL { public static string Build(GenerateSQLInput config) { if (config.SelectConfigs == null || !config.SelectConfigs.Any()) throw new ArgumentException("至少需要一个选择配置"); StringBuilder sql = new StringBuilder(); // SELECT clause sql.Append("SELECT "); sql.Append(string.Join(", ", config.SelectConfigs.Select(sc => $"{sc.Table}.{sc.Column}"))); sql.AppendLine(); // 确定主表(出现频率最高的表) var mainTable = DetermineMainTable(config); sql.AppendLine($"FROM {mainTable}"); // 收集所有涉及的表 var allTables = CollectAllTables(config); var joinedTables = new HashSet(StringComparer.OrdinalIgnoreCase) { mainTable }; // 处理JOIN关系 - 优化后的逻辑 ProcessJoins(sql, config.JoinConfigs, joinedTables, allTables); // 添加剩余未连接的表(使用CROSS JOIN) AddRemainingTables(sql, allTables, joinedTables); // WHERE子句 ProcessWhereClause(sql, config.WhereConfigs); // ORDER BY子句 ProcessOrderByClause(sql, config.OrderConfigs); return sql.ToString(); } private static string DetermineMainTable(GenerateSQLInput config) { // 统计所有表出现的频率 var tableFrequency = new Dictionary(StringComparer.OrdinalIgnoreCase); // 统计SELECT中的表 foreach (var sc in config.SelectConfigs) { if (tableFrequency.ContainsKey(sc.Table)) tableFrequency[sc.Table]++; else tableFrequency[sc.Table] = 1; } // 统计JOIN中的表 foreach (var jc in config.JoinConfigs) { if (tableFrequency.ContainsKey(jc.LeftTable)) tableFrequency[jc.LeftTable]++; else tableFrequency[jc.LeftTable] = 1; if (tableFrequency.ContainsKey(jc.RightTable)) tableFrequency[jc.RightTable]++; else tableFrequency[jc.RightTable] = 1; } // 统计WHERE中的表 foreach (var wc in config.WhereConfigs) { if (tableFrequency.ContainsKey(wc.Table)) tableFrequency[wc.Table]++; else tableFrequency[wc.Table] = 1; } // 统计ORDER BY中的表 foreach (var oc in config.OrderConfigs) { if (tableFrequency.ContainsKey(oc.Table)) tableFrequency[oc.Table]++; else tableFrequency[oc.Table] = 1; } // 选择出现频率最高的表作为主表 return tableFrequency.OrderByDescending(kv => kv.Value) .ThenBy(kv => kv.Key) .FirstOrDefault().Key; } private static HashSet CollectAllTables(GenerateSQLInput config) { var allTables = new HashSet(StringComparer.OrdinalIgnoreCase); config.SelectConfigs?.ForEach(sc => allTables.Add(sc.Table)); config.JoinConfigs?.ForEach(jc => { allTables.Add(jc.LeftTable); allTables.Add(jc.RightTable); }); config.WhereConfigs?.ForEach(wc => allTables.Add(wc.Table)); config.OrderConfigs?.ForEach(oc => allTables.Add(oc.Table)); return allTables; } private static void ProcessJoins(StringBuilder sql, List joinConfigs, HashSet joinedTables, HashSet allTables) { if (joinConfigs == null) return; // 使用队列处理所有JOIN关系 var joinQueue = new Queue(joinConfigs); var processedJoins = new HashSet(); bool progressMade; do { progressMade = false; var currentQueue = new Queue(joinQueue); joinQueue.Clear(); while (currentQueue.Count > 0) { var join = currentQueue.Dequeue(); // 如果右表已经连接,跳过 if (joinedTables.Contains(join.RightTable)) { processedJoins.Add(join); continue; } // 如果左表已连接,可以处理这个JOIN if (joinedTables.Contains(join.LeftTable)) { // 构建ON条件 var onConditions = join.TableColumns.Select(tc => $"{join.LeftTable}.{tc.LeftTableColumn} = " + $"{join.RightTable}.{tc.RightTableColumn}"); sql.AppendLine($"{join.JoinType} {join.RightTable} ON {string.Join(" AND ", onConditions)}"); joinedTables.Add(join.RightTable); processedJoins.Add(join); progressMade = true; } else { // 左表未连接,放回队列稍后处理 joinQueue.Enqueue(join); } } // 如果还有未处理的JOIN但队列未变化,尝试添加缺失的表 if (!progressMade && joinQueue.Count > 0) { var nextJoin = joinQueue.Peek(); // 如果左表不在已连接表中,尝试添加它 if (!joinedTables.Contains(nextJoin.LeftTable) && allTables.Contains(nextJoin.LeftTable)) { sql.AppendLine($", {nextJoin.LeftTable}"); joinedTables.Add(nextJoin.LeftTable); progressMade = true; } } } while (progressMade && joinQueue.Count > 0); // 处理剩余无法连接的JOIN foreach (var join in joinQueue) { // 如果右表已经连接,跳过 if (joinedTables.Contains(join.RightTable)) continue; // 尝试添加左表 if (!joinedTables.Contains(join.LeftTable)) { sql.AppendLine($", {join.LeftTable}"); joinedTables.Add(join.LeftTable); } // 构建ON条件 var onConditions = join.TableColumns.Select(tc => $"{join.LeftTable}.{tc.LeftTableColumn} = " + $"{join.RightTable}.{tc.RightTableColumn}"); sql.AppendLine($"{join.JoinType} {join.RightTable} ON {string.Join(" AND ", onConditions)}"); joinedTables.Add(join.RightTable); } } private static void AddRemainingTables(StringBuilder sql, HashSet allTables, HashSet joinedTables) { var remainingTables = allTables.Except(joinedTables, StringComparer.OrdinalIgnoreCase).ToList(); if (!remainingTables.Any()) return; foreach (var table in remainingTables) { sql.AppendLine($", {table}"); joinedTables.Add(table); } } private static void ProcessWhereClause(StringBuilder sql, List whereConfigs) { if (whereConfigs == null || !whereConfigs.Any()) return; sql.Append("WHERE "); foreach (var where in whereConfigs) { string formattedValue = FormatValue(where.Value, where.DataType, where.Operator); sql.Append($"{where.Table}.{where.Column} " + $"{where.Operator} {formattedValue} {where.JoinType} "); } // 移除最后一个逻辑运算符 sql.Length -= 4; sql.AppendLine(); } private static void ProcessOrderByClause(StringBuilder sql, List orderConfigs) { if (orderConfigs == null || !orderConfigs.Any()) return; sql.Append("ORDER BY "); sql.Append(string.Join(", ", orderConfigs.OrderBy(oc => oc.Sort).Select(oc => $"{oc.Table}.{oc.Column}"))); } /// /// WHERE 数值格式化 /// /// /// /// /// private static string FormatValue(object value, string dataType, string operatorType) { if (value == null) return "NULL"; string valueStr = value.ToString(); if (string.IsNullOrWhiteSpace(valueStr)) return "NULL"; // 根据数据类型和操作符格式化值 if (dataType?.ToLower().Contains("varchar") == true || dataType?.ToLower().Contains("text") == true || dataType?.ToLower().Contains("bool") == true || dataType?.ToLower().Contains("datetime") == true || dataType?.ToLower().Contains("timestamp") == true || value is string) { // 对于LIKE操作符,添加通配符 if (operatorType?.ToUpper() == "LIKE") { return $"'%{valueStr}%'"; } else { return $"'{valueStr}'"; } } else { // 数字类型直接返回 return valueStr; } } }