using MiaoYu.Repository.Admin.Entities.LowCode;
using MiaoYu.Shared.Admin.Models.LowCodes;
using CoreIDatabaseTableService = MiaoYu.Core.CodeGenerator.Services.IDatabaseTableService;
using CoreLowCodeTableInfo = MiaoYu.Core.CodeGenerator.Models.LowCodeTableInfo;
using CoreITableMetaConfigService = MiaoYu.Core.CodeGenerator.Services.ITableMetaConfigService;
using CoreGenDbTableDto = MiaoYu.Core.CodeGenerator.Models.GenDbTableDto;
using CoreTableMetaConfig = MiaoYu.Core.CodeGenerator.Models.TableMetaConfig;
using CoreColumnMetaConfig = MiaoYu.Core.CodeGenerator.Models.ColumnMetaConfig;
namespace MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl;
///
/// 服务 Low_Code_Table_InfoService
///
public class LowCodeTableInfoService : ApplicationService>
{
private readonly CoreIDatabaseTableService _databaseTableService;
private readonly IRepository _lowCodeTableRepository;
private readonly CoreITableMetaConfigService _tableMetaConfigService;
private readonly ILogger? _logger;
public LowCodeTableInfoService(
CoreIDatabaseTableService databaseTableService,
IRepository defaultRepository,
IRepository lowCodeTableRepository,
CoreITableMetaConfigService tableMetaConfigService,
ILogger? logger = null) : base(defaultRepository)
{
_databaseTableService = databaseTableService;
_lowCodeTableRepository = lowCodeTableRepository;
_tableMetaConfigService = tableMetaConfigService;
_logger = logger;
}
///
/// 根据表名和数据库标识获取列列表(推荐使用)
///
/// 查询参数,包含表名和数据库标识
///
public Task FindListByTableAsync(TableColumnQueryInput input)
{
// 参数验证
if (string.IsNullOrWhiteSpace(input.TableName) || string.IsNullOrWhiteSpace(input.DataBase))
{
return Task.FromResult(new PagingView(input.Page, input.Size));
}
// 从 Core 层获取所有表信息(已包含配置合并)
var allTables = _databaseTableService.GetAllTables();
// 直接使用表名和数据库标识查找目标表
var targetTable = allTables.FirstOrDefault(t =>
t.TableName == input.TableName && t.DataBase == input.DataBase);
if (targetTable == null || targetTable.TableInfos == null)
{
return Task.FromResult(new PagingView(input.Page, input.Size));
}
// 应用筛选条件
var columns = targetTable.TableInfos.AsEnumerable();
if (!string.IsNullOrWhiteSpace(input.Search?.ColumnName))
{
columns = columns.Where(w => w.ColumnName != null && w.ColumnName.Contains(input.Search.ColumnName));
}
if (!string.IsNullOrWhiteSpace(input.Search?.Describe))
{
columns = columns.Where(w => w.Describe != null && w.Describe.Contains(input.Search.Describe));
}
// 排序和分页
var orderedColumns = columns
.OrderBy(w => w.Position)
.Skip((input.Page - 1) * input.Size)
.Take(input.Size)
.Select(w => new Dictionary
{
["id"] = Guid.NewGuid(), // 临时 ID,因为是从内存查询
["isPrimary"] = w.IsPrimary,
["isIdentity"] = w.IsIdentity,
["isNullable"] = w.IsNullable,
["position"] = w.Position,
["columnName"] = w.ColumnName,
["describe"] = w.Describe,
["databaseColumnType"] = w.DatabaseColumnType,
["csType"] = w.CsType,
["csField"] = w.CsField,
["displayName"] = w.DisplayName,
["tableName"] = input.TableName,
["dataBase"] = input.DataBase,
["lastModificationTime"] = DateTime.Now.ToString("yyyy-MM-dd"),
["creationTime"] = DateTime.Now.ToString("yyyy-MM-dd"),
["isTableColumnShow"] = w.IsTableColumnShow ?? true,
["isTableSelect"] = w.IsTableSelect,
["isImageId"] = w.IsImageId,
["orderById"] = w.OrderById ?? 10,
["width"] = w.Width,
["maxLength"] = w.MaxLength
})
.ToList();
return Task.FromResult(new PagingView(input.Page, input.Size)
{
Total = columns.Count(),
DataSource = orderedColumns,
PageCount = (columns.Count() + input.Size - 1) / input.Size
});
}
///
/// 获取列表数据(从 Core 层查询表结构并合并配置)
///
///
///
[Obsolete("请使用 FindListByTableAsync 方法,该方法使用 TableName + DataBase 作为查询参数")]
public async Task FindListAsync(PagingSearchInput pagingSearchInput)
{
// ✅ 从 Core 层获取所有表信息(已包含配置合并)
var allTables = _databaseTableService.GetAllTables();
// 根据 Low_Code_TableId 查找对应的表名和数据库
string? targetTableName = null;
string? targetDatabase = null;
if (pagingSearchInput.Search.Low_Code_TableId != Guid.Empty)
{
var lowCodeTable = await _lowCodeTableRepository.FindAsync(w => w.Id == pagingSearchInput.Search.Low_Code_TableId);
if (lowCodeTable != null)
{
targetTableName = lowCodeTable.TableName;
targetDatabase = lowCodeTable.DataBase;
}
}
// 筛选目标表
var targetTable = allTables.FirstOrDefault(t =>
t.TableName == targetTableName && t.DataBase == targetDatabase);
if (targetTable == null || targetTable.TableInfos == null)
{
return new PagingView(pagingSearchInput.Page, pagingSearchInput.Size);
}
// 应用筛选条件
var columns = targetTable.TableInfos.AsEnumerable();
if (!string.IsNullOrWhiteSpace(pagingSearchInput.Search.ColumnName))
{
columns = columns.Where(w => w.ColumnName != null && w.ColumnName.Contains(pagingSearchInput.Search.ColumnName));
}
if (!string.IsNullOrWhiteSpace(pagingSearchInput.Search.Describe))
{
columns = columns.Where(w => w.Describe != null && w.Describe.Contains(pagingSearchInput.Search.Describe));
}
// 排序和分页
var orderedColumns = columns
.OrderBy(w => w.Position)
.Skip((pagingSearchInput.Page - 1) * pagingSearchInput.Size)
.Take(pagingSearchInput.Size)
.Select(w => new Dictionary
{
["id"] = Guid.NewGuid(), // 临时 ID,因为是从内存查询
["isPrimary"] = w.IsPrimary,
["isIdentity"] = w.IsIdentity,
["isNullable"] = w.IsNullable,
["position"] = w.Position,
["columnName"] = w.ColumnName,
["describe"] = w.Describe,
["databaseColumnType"] = w.DatabaseColumnType,
["csType"] = w.CsType,
["csField"] = w.CsField,
["displayName"] = w.DisplayName,
["low_Code_TableId"] = pagingSearchInput.Search.Low_Code_TableId,
["lastModificationTime"] = DateTime.Now.ToString("yyyy-MM-dd"),
["creationTime"] = DateTime.Now.ToString("yyyy-MM-dd"),
["isTableColumnShow"] = w.IsTableColumnShow ?? true,
["isTableSelect"] = w.IsTableSelect,
["isImageId"] = w.IsImageId,
["orderById"] = w.OrderById ?? 10,
["width"] = w.Width,
["maxLength"] = w.MaxLength
})
.ToList();
return new PagingView(pagingSearchInput.Page, pagingSearchInput.Size)
{
Total = columns.Count(),
DataSource = orderedColumns,
PageCount = (columns.Count() + pagingSearchInput.Size - 1) / pagingSearchInput.Size
};
}
///
/// 根据id数组删除
///
///
///
public Task DeleteListAsync(List ids)
{
_databaseTableService.ClearAllTablesByCache();
return _defaultRepository.DeleteByIdsAsync(ids);
}
///
/// 根据表名和数据库标识同步字段(推荐使用)
///
/// 同步参数,包含表名和数据库标识
///
/// 参数验证失败或表不存在时抛出
public Task SynchronizationByTableAsync(TableSyncInput input)
{
// 参数验证
if (input == null)
throw new ArgumentException("参数不能为空", nameof(input));
if (string.IsNullOrWhiteSpace(input.TableName))
throw new ArgumentException("表名不能为空", nameof(input));
if (string.IsNullOrWhiteSpace(input.DataBase))
throw new ArgumentException("数据库标识不能为空", nameof(input));
// 清除缓存并重新加载
_databaseTableService.ClearAllTablesByCache();
_databaseTableService.RefreshCache();
// 验证表是否存在
var allTables = _databaseTableService.GetAllTables();
var targetTable = allTables.FirstOrDefault(t =>
t.TableName == input.TableName && t.DataBase == input.DataBase);
if (targetTable == null)
throw new ArgumentException($"指定的表不存在:表名={input.TableName}, 数据库={input.DataBase}", nameof(input));
return Task.FromResult(true);
}
///
/// 同步表
///
///
///
///
[Obsolete("请使用 SynchronizationByTableAsync 方法,该方法使用 TableName + DataBase 作为查询参数")]
public async Task SynchronizationColumnByTableIdAsync(Guid tableId, bool isTableSync = false)
{
var allTables = _databaseTableService.GetAllTableInfos();
var table = await _lowCodeTableRepository.FindAsync(w => w.Id == tableId);
// 修复:同时匹配表名和数据库标识
var tableInfo = allTables.Find(w =>
w.Name == table.TableName && w.DataBase == table.DataBase);
//查询出当前表所有的字段
var tableColumns = await _defaultRepository.ToListAsync(w => w.Low_Code_TableId == table.Id);
//操作集合
var list = new List();
if (isTableSync)
{
if (tableColumns != null && tableColumns.Count == 0)
{
foreach (var item in tableInfo.Columns)
{
// if (tableColumns.Any(w => w.ColumnName == item.Name)) continue;
var model = new LowCodeTableInfo();
model.IsPrimary = item.IsPrimary;
model.IsIdentity = item.IsIdentity;
model.IsNullable = item.IsNullable;
model.Position = item.Position;
model.Low_Code_TableId = table.Id;
model.ColumnName = item.Name;
model.DatabaseColumnType = item.DbType;
model.CsType = item.CsType;
model.CsField = item.Name;
model.MaxLength = item.MaxLength;
//model.IsImageId = item.IsImageId;
//model.IsImageId = item.IsImageId;
//model.IsImageId = item.IsImageId;
if (!string.IsNullOrWhiteSpace(item.Comment))
{
model.Describe = item.Comment;
model.DisplayName = item.Comment;
}
list.Add(model);
}
}
}
else
{
foreach (var item in tableInfo.Columns)
{
// if (tableColumns.Any(w => w.ColumnName == item.Name)) continue;
var model = new LowCodeTableInfo();
model.IsPrimary = item.IsPrimary;
model.IsIdentity = item.IsIdentity;
model.IsNullable = item.IsNullable;
model.Position = item.Position;
model.Low_Code_TableId = table.Id;
model.ColumnName = item.Name;
model.DatabaseColumnType = item.DbType;
model.CsType = item.CsType;
model.CsField = item.Name;
model.MaxLength = item.MaxLength;
if (!string.IsNullOrWhiteSpace(item.Comment))
{
model.Describe = item.Comment;
model.DisplayName = item.Comment;
}
var oldColumns = tableColumns.FirstOrDefault(w => w.ColumnName == item.Name);
if (oldColumns!=null)
{
model.OrderById = oldColumns.OrderById;
model.Describe = oldColumns.Describe;
model.IsImageId = oldColumns.IsImageId;
model.IsTableColumnShow = oldColumns.IsTableColumnShow;
model.IsTableSelect = oldColumns.IsTableSelect;
model.Width = oldColumns.Width;
};
list.Add(model);
}
}
await _defaultRepository.DeleteAsync(w => w.Low_Code_TableId == table.Id);
await _defaultRepository.InsertRangeAsync(list);
_databaseTableService.ClearAllTablesByCache();
}
///
/// 根据表名和数据库标识变更列配置(推荐使用)
///
/// 修改参数,包含表名、数据库标识和列配置列表
/// 保存成功返回 true
/// 参数验证失败或表不存在时抛出
public async Task ChangeByTableAsync(TableColumnChangeInput input)
{
// 参数验证
if (input == null)
throw new ArgumentException("参数不能为空", nameof(input));
if (string.IsNullOrWhiteSpace(input.TableName))
throw new ArgumentException("表名不能为空", nameof(input));
if (string.IsNullOrWhiteSpace(input.DataBase))
throw new ArgumentException("数据库标识不能为空", nameof(input));
if (input.Columns == null || input.Columns.Count == 0)
throw new ArgumentException("列配置列表不能为空", nameof(input));
// 验证所有列的 ColumnName 不为空
var invalidColumns = input.Columns.Where(c => string.IsNullOrWhiteSpace(c.ColumnName)).ToList();
if (invalidColumns.Count > 0)
throw new ArgumentException("列配置中存在空的列名", nameof(input));
// 清除缓存
_databaseTableService.ClearAllTablesByCache();
// 从内存缓存中查找表
var allTables = _databaseTableService.GetAllTables();
var targetTable = allTables.FirstOrDefault(t =>
t.TableName == input.TableName && t.DataBase == input.DataBase);
if (targetTable == null)
throw new ArgumentException($"指定的表不存在:表名={input.TableName}, 数据库={input.DataBase}", nameof(input));
if (targetTable.TableInfos == null)
throw new ArgumentException("表列信息为空", nameof(input));
// 更新用户修改的列配置
var updatedCount = 0;
foreach (var changedColumn in input.Columns)
{
var existingColumn = targetTable.TableInfos.FirstOrDefault(c => c.ColumnName == changedColumn.ColumnName);
if (existingColumn == null)
{
// 列不存在,记录日志但继续处理其他列
_logger?.LogWarning($"列不存在,跳过更新:表名={input.TableName}, 列名={changedColumn.ColumnName}");
continue;
}
// 更新可配置字段
// 注意:由于 JsonExtensionData 只能捕获未定义的属性,而我们的字段都已定义,
// 所以无法通过 WasFieldProvided 检测。我们采用以下策略:
// 1. 前端总是传递所有字段(包括 null)
// 2. 我们直接更新所有字段(字符串 null = 清空,可空值类型 null = 设置为 null)
// 字符串字段:直接更新(null = 清空,有值 = 更新)
existingColumn.DisplayName = changedColumn.DisplayName;
existingColumn.Describe = changedColumn.Describe;
existingColumn.CsField = changedColumn.CsField;
existingColumn.Width = changedColumn.Width;
// 可空值类型:直接更新(null = 设置为 null,有值 = 设置为该值)
existingColumn.IsTableColumnShow = changedColumn.IsTableColumnShow;
existingColumn.IsTableSelect = changedColumn.IsTableSelect;
existingColumn.IsImageId = changedColumn.IsImageId;
existingColumn.OrderById = changedColumn.OrderById;
updatedCount++;
}
if (updatedCount == 0)
{
throw new ArgumentException("没有成功更新任何列配置,请检查列名是否正确", nameof(input));
}
// 保存到配置文件
await SaveTableMetaConfigAsync(targetTable);
// 清除缓存,确保下次查询时重新加载并合并最新的配置文件
_databaseTableService.ClearAllTablesByCache();
return true;
}
///
/// 变更数据(保存到配置文件)
///
///
///
[Obsolete("请使用 ChangeByTableAsync 方法,该方法使用 TableName + DataBase 作为查询参数")]
public async Task ChangeAsync(List lowCodeTableInfos)
{
// 清除缓存
_databaseTableService.ClearAllTablesByCache();
// 按表分组保存
var groupedByTable = lowCodeTableInfos.GroupBy(c => c.Low_Code_TableId);
foreach (var group in groupedByTable)
{
var tableId = group.Key;
var lowCodeTable = await _lowCodeTableRepository.FindAsync(w => w.Id == tableId);
if (lowCodeTable == null || string.IsNullOrEmpty(lowCodeTable.DataBase) || string.IsNullOrEmpty(lowCodeTable.TableName))
continue;
// 获取完整的表信息(包含所有列)
var allTables = _databaseTableService.GetAllTables();
var targetTable = allTables.FirstOrDefault(t =>
t.TableName == lowCodeTable.TableName &&
t.DataBase == lowCodeTable.DataBase);
if (targetTable == null)
continue;
// 更新用户修改的列配置
foreach (var changedColumn in group)
{
var existingColumn = targetTable.TableInfos?.FirstOrDefault(c => c.ColumnName == changedColumn.ColumnName);
if (existingColumn != null)
{
existingColumn.DisplayName = changedColumn.DisplayName;
existingColumn.Describe = changedColumn.Describe;
existingColumn.CsField = changedColumn.CsField;
existingColumn.IsTableSelect = changedColumn.IsTableSelect;
existingColumn.IsImageId = changedColumn.IsImageId;
existingColumn.IsTableColumnShow = changedColumn.IsTableColumnShow;
existingColumn.OrderById = changedColumn.OrderById;
existingColumn.Width = changedColumn.Width;
}
}
// 保存到配置文件
await SaveTableMetaConfigAsync(targetTable);
}
// 注意:不再更新数据库表,改为更新配置文件
// await _defaultRepository.UpdateRangeAsync(lowCodeTableInfos);
}
///
/// 保存表元信息到配置文件
///
private async Task SaveTableMetaConfigAsync(CoreGenDbTableDto tableDto)
{
if (string.IsNullOrEmpty(tableDto.DataBase) || string.IsNullOrEmpty(tableDto.TableName))
return;
var config = new CoreTableMetaConfig
{
DisplayName = tableDto.DisplayName,
EntityName = tableDto.EntityName,
Remark = tableDto.Remark,
ModelPath = tableDto.ModelPath,
ServicePath = tableDto.ServicePath,
ControllerPath = tableDto.ControllerPath,
ClientIndexPath = tableDto.ClientIndexPath,
ClientInfoPath = tableDto.ClientInfoPath,
ClientServicePath = tableDto.ClientServicePath,
IsCover = tableDto.IsCover ?? false,
Columns = new Dictionary()
};
// 保存列配置
if (tableDto.TableInfos != null)
{
foreach (var column in tableDto.TableInfos)
{
if (!string.IsNullOrEmpty(column.ColumnName))
{
config.Columns[column.ColumnName] = new CoreColumnMetaConfig
{
DisplayName = column.DisplayName,
Describe = column.Describe,
CsField = column.CsField,
IsTableSelect = column.IsTableSelect,
IsImageId = column.IsImageId,
IsTableColumnShow = column.IsTableColumnShow,
Width = column.Width,
OrderById = column.OrderById
};
}
}
}
await _tableMetaConfigService.SaveConfigAsync(tableDto.DataBase!, tableDto.TableName!, config);
}
}