using WIDESEA_Builder.Utility;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyModel;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core.Const;
using WIDESEA_Core.DBManager;
using WIDESEA_Core.Enums;
using WIDESEA_Core.Extensions;
using WIDESEA_Core.ManageUser;
using WIDESEA_Core.Utilities;
using WIDESEA_Entity.DomainModels;
using WIDESEA_Entity.DomainModels.Sys;
using WIDESEA_Entity.SystemModels;
namespace WIDESEA_Builder.Services
{
public partial class Sys_TableInfoService
{
private int totalWidth = 0;
private int totalCol = 0;
private string webProject = null;
private string apiNameSpace = null;
private string startName = "";
private string StratName
{
get
{
if (startName == "")
{
startName = WebProject.Substring(0, webProject.LastIndexOf('_'));
}
return startName;
}
}
private string WebProject
{
get
{
if (webProject != null)
return webProject;
webProject = ProjectPath.GetLastIndexOfDirectoryName("_WebApi") ?? ProjectPath.GetLastIndexOfDirectoryName("Api") ?? ProjectPath.GetLastIndexOfDirectoryName(".Web");
if (webProject == null)
{
throw new Exception("未获取到以.WebApi结尾的项目名称,无法创建页面");
}
return webProject;
}
}
private string ApiNameSpace
{
get
{
if (apiNameSpace != null)
return apiNameSpace;
apiNameSpace = ProjectPath.GetLastIndexOfDirectoryName(".WebApi");
if (apiNameSpace == null)
{
throw new Exception("未获取到以.WebApi,无法创建Api控制器");
}
return apiNameSpace;
}
}
///
/// 获取生成配置的树开菜单
///
///
public async Task<(string, string)> GetTableTree()
{
var treeData = await repository.FindAsIQueryable(x => 1 == 1)
.Select(c => new
{
id = c.Table_Id,
pId = c.ParentId,
parentId = c.ParentId,
name = c.ColumnCNName,
orderNo = c.OrderNo
}).OrderByDescending(c => c.orderNo).ToListAsync();
var treeList = treeData.Select(a => new
{
a.id,
a.pId,
a.parentId,
a.name,
isParent = treeData.Select(x => x.pId).Contains(a.id)
});
string startsWith = WebProject.Substring(0, WebProject.IndexOf('_'));
return (treeList.Count() == 0 ? "[]" : treeList.Serialize() ?? "", ProjectPath.GetProjectFileName(startsWith));
;
}
///
/// 2020.05.17增加mysql获取表结构时区分当前所在数据库
///
///
private string GetMysqlTableSchema()
{
try
{
string dbName = DBServerProvider.GetConnectionString().Split("Database=")[1].Split(";")[0]?.Trim();
if (!string.IsNullOrEmpty(dbName))
{
dbName = $" and table_schema = '{dbName}' ";
}
return dbName;
}
catch (Exception ex)
{
Console.WriteLine($"获取mysql数据库名异常:{ex.Message}");
return "";
}
}
///
/// 获取Mysql表结构信息
/// 2020.06.14增加对mysql数据类型double区分
///
///
private string GetMySqlModelInfo()
{
return $@"SELECT
DISTINCT
CONCAT(NUMERIC_PRECISION,',',NUMERIC_SCALE) as Prec_Scale,
CASE
WHEN data_type IN( 'BIT', 'BOOL','bit', 'bool') THEN
'bool'
WHEN data_type in('smallint','SMALLINT') THEN 'short'
WHEN data_type in('tinyint', 'TINYINT') THEN 'sbyte'
WHEN data_type IN('MEDIUMINT','mediumint', 'int','INT','year', 'Year') THEN
'int'
WHEN data_type in ( 'BIGINT','bigint') THEN
'bigint'
WHEN data_type IN('FLOAT', 'DECIMAL','float', 'decimal') THEN
'decimal'
WHEN data_type IN( 'DOUBLE', 'double') THEN
'double'
WHEN data_type IN('CHAR', 'VARCHAR', 'TINY TEXT', 'TEXT', 'MEDIUMTEXT', 'LONGTEXT', 'TINYBLOB', 'BLOB', 'MEDIUMBLOB', 'LONGBLOB', 'Time','char', 'varchar', 'tiny text', 'text', 'mediumtext', 'longtext', 'tinyblob', 'blob', 'mediumblob', 'longblob', 'time') THEN
'nvarchar'
WHEN data_type IN('Date', 'DateTime', 'TimeStamp','date', 'datetime', 'timestamp') THEN
'datetime' ELSE 'nvarchar'
END AS ColumnType, Column_Name AS ColumnName
FROM
information_schema.COLUMNS
WHERE
table_name = ?tableName {GetMysqlTableSchema()};";
}
///
/// 获取SqlServer表结构信息
///
///
private string GetSqlServerModelInfo()
{
return $@"
SELECT CASE WHEN t.ColumnType IN ('DECIMAL','smallmoney','money') THEN
CONVERT(VARCHAR(30),t.Prec)+','+CONVERT(VARCHAR(30),t.Scale) ELSE ''
END
AS Prec_Scale,t.ColumnType,t.ColumnName
FROM (
SELECT col.prec AS 'Prec',col.scale AS 'Scale',t.name AS ColumnType,col.name AS ColumnName FROM dbo.syscolumns col
LEFT JOIN dbo.systypes t ON col.xtype = t.xusertype
INNER JOIN dbo.sysobjects obj ON col.id = obj.id
AND obj.xtype IN ('U','V')
AND obj.status >= 0
LEFT JOIN dbo.syscomments comm ON col.cdefault = comm.id
LEFT JOIN sys.extended_properties ep ON col.id = ep.major_id
AND col.colid = ep.minor_id
AND ep.name = 'MS_Description'
LEFT JOIN sys.extended_properties epTwo ON obj.id = epTwo.major_id
AND epTwo.minor_id = 0
AND epTwo.name = 'MS_Description'
WHERE obj.name =@tableName) AS t";
}
///
/// 获取PgSQl表结构信息
/// 2020.08.07完善PGSQL
///
///
///
///
///
private string GetPgSqlModelInfo()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(" SELECT ");
stringBuilder.Append(" col.COLUMN_NAME AS \"ColumnName\", ");
stringBuilder.Append(" CASE ");
stringBuilder.Append(" WHEN col.udt_name = 'uuid' THEN ");
stringBuilder.Append(" 'guid' ");
stringBuilder.Append(" WHEN col.udt_name IN ( 'int2') THEN ");
stringBuilder.Append(" 'short' ");
stringBuilder.Append(" WHEN col.udt_name IN ( 'int4' ) THEN ");
stringBuilder.Append(" 'int' ");
stringBuilder.Append(" WHEN col.udt_name = 'int8' THEN ");
stringBuilder.Append(" 'long' ");
stringBuilder.Append(" WHEN col.udt_name IN ( 'char', 'varchar', 'text', 'xml', 'bytea' ) THEN ");
stringBuilder.Append(" 'string' ");
stringBuilder.Append(" WHEN col.udt_name IN ( 'bool' ) THEN ");
stringBuilder.Append(" 'bool' ");
stringBuilder.Append(" WHEN col.udt_name IN ( 'date','timestamp' ) THEN ");
stringBuilder.Append(" 'DateTime' ");
stringBuilder.Append(" WHEN col.udt_name IN ( 'decimal', 'money','numeric' ) THEN ");
stringBuilder.Append(" 'decimal' ");
stringBuilder.Append(" WHEN col.udt_name IN ( 'float4', 'float8' ) THEN ");
stringBuilder.Append(" 'float' ELSE'string ' ");
stringBuilder.Append(" END as ColumnType ");
stringBuilder.Append("from information_schema.COLUMNS col ");
stringBuilder.Append("WHERE \"lower\" ( TABLE_NAME ) = \"lower\" (@tableName ) ");
return stringBuilder.ToString();
}
private WebResponseContent ExistsTable(string tableName, string tableTrueName)
{
WebResponseContent webResponse = new WebResponseContent(true);
//如果是第一次创建model,此处反射获取到的是已经缓存过的文件,必须重新运行项目否则新增的文件无法做判断文件是否创建,需要重新做反射实际文件,待修改...
var compilationLibrary = DependencyContext
.Default
.CompileLibraries
.Where(x => !x.Serviceable && x.Type == "project");
foreach (var _compilation in compilationLibrary)
{
try
{
foreach (var entity in AssemblyLoadContext.Default
.LoadFromAssemblyName(new AssemblyName(_compilation.Name))
.GetTypes().Where(x => x.GetTypeInfo().BaseType != null
&& x.BaseType == typeof(BaseEntity)))
{
if (entity.Name == tableTrueName && !string.IsNullOrEmpty(tableName) && tableName != tableTrueName)
return webResponse.Error($"实际表名【{tableTrueName}】已创建实体,不能创建别名【{tableName}】实体");
if (entity.Name != tableName)
{
var tableAttr = entity.GetCustomAttribute();
if (tableAttr != null && tableAttr.Name == tableTrueName)
{
return webResponse.Error($"实际表名【{tableTrueName}】已被【{entity.Name}】创建建实体,不能创建别名【{tableName}】实体,请将别名更换为【{entity.Name}】");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("查找文件异常:" + ex.Message);
}
}
return webResponse;
}
///
/// 生成实体Model
///
///
///
public string CreateEntityModel(Sys_TableInfo sysTableInfo)
{
if (sysTableInfo == null
|| sysTableInfo.TableColumns == null
|| sysTableInfo.TableColumns.Count == 0)
return "提交的配置数据不完整";
WebResponseContent webResponse = ValidColumnString(sysTableInfo);
if (!webResponse.Status)
return webResponse.Message;
string tableName = sysTableInfo.TableName;
webResponse = ExistsTable(tableName, sysTableInfo.TableTrueName);
if (!webResponse.Status)
{
return webResponse.Message;
}
if (!string.IsNullOrEmpty(sysTableInfo.TableTrueName) && sysTableInfo.TableTrueName != tableName)
{
tableName = sysTableInfo.TableTrueName;
}
string sql = "";
switch (DBType.Name)
{
case "MySql":
sql = GetMySqlModelInfo();
break;
case "PgSql":
sql = GetPgSqlModelInfo();
break;
default:
sql = GetSqlServerModelInfo();
break;
}
List tableColumnInfoList = repository.DapperContext.QueryList(sql, new { tableName });
List list = sysTableInfo.TableColumns;
string msg = CreateEntityModel(list, sysTableInfo, tableColumnInfoList, 1);
if (msg != "")
return msg;
//if (list.Any(c => c.ApiInPut > 0))
//{
// CreateEntityModel(list.Where(c => c.ApiInPut > 0).ToList(), sysTableInfo, tableColumnInfoList, 2);
//}
//if (list.Any(c => c.ApiOutPut > 0))
//{
// CreateEntityModel(list.Where(c => c.ApiOutPut > 0).ToList(), sysTableInfo, tableColumnInfoList, 3);
//}
return "Model创建成功!";
}
///
/// 保存配置信息
///
///
///
public WebResponseContent SaveEidt(Sys_TableInfo sysTableInfo)
{
WebResponseContent webResponse = ValidColumnString(sysTableInfo);
if (!webResponse.Status) return webResponse;
//2020.05.07新增禁止选择上级角色为自己
if (sysTableInfo.Table_Id == sysTableInfo.ParentId)
{
return WebResponseContent.Instance.Error($"父级id不能为自己");
}
if (sysTableInfo.TableColumns != null && sysTableInfo.TableColumns.Any(x => !string.IsNullOrEmpty(x.DropNo) && x.ColumnName == sysTableInfo.ExpressField))
{
return WebResponseContent.Instance.Error($"不能将字段【{sysTableInfo.ExpressField}】设置为快捷编辑,因为已经设置了数据源");
}
if (sysTableInfo.TableColumns != null)
{
sysTableInfo.TableColumns.ForEach(x =>
{
x.TableName = sysTableInfo.TableName;
});
}
sysTableInfo.TableColumns?.ForEach(x =>
{
if (x.IsReadDataset == null)
{
x.IsReadDataset = 0;
}
});
return repository.UpdateRange(sysTableInfo, true, true, null, null, true);
}
///
/// 2020.08.07完善PGSQL
///
///
///
private string GetCurrentSql(string tableName)
{
string sql;
if (DBType.Name.ToLower() == DbCurrentType.MySql.ToString().ToLower())
{
sql = GetMySqlStructure(tableName);
}
else if (DBType.Name.ToLower() == DbCurrentType.PgSql.ToString().ToLower())
{
sql = GetPgSqlStructure(tableName);
}
else
{
sql = GetSqlServerStructure(tableName);
}
return sql;
}
///
/// 将表结构重新同步到代码生成配置
///
///
///
public async Task SyncTable(string tableName)
{
WebResponseContent webResponse = new WebResponseContent();
if (string.IsNullOrEmpty(tableName)) return webResponse.OK("表名不能为空");
Sys_TableInfo tableInfo = repository.FindAsIQueryable(x => x.TableName == tableName)
.Include(o => o.TableColumns).FirstOrDefault();
if (tableInfo == null)
return webResponse.Error("未获取到【" + tableName + "】的配置信息,请使用新建功能");
if (!string.IsNullOrEmpty(tableInfo.TableTrueName) && tableInfo.TableTrueName != tableName)
{
tableName = tableInfo.TableTrueName;
}
string sql = GetCurrentSql(tableName);
//获取表结构
List columns = repository.DapperContext
.QueryList(sql, new { tableName });
if (columns == null || columns.Count == 0)
return webResponse.Error("未获取到【" + tableName + "】表结构信息,请确认表是否存在");
//获取现在配置好的表结构
List detailList = tableInfo.TableColumns ?? new List();
List addColumns = new List();
List updateColumns = new List();
foreach (Sys_TableColumn item in columns)
{
Sys_TableColumn tableColumn = detailList.Where(x => x.ColumnName == item.ColumnName)
.FirstOrDefault();
//新加的列
if (tableColumn == null)
{
item.TableName = tableInfo.TableName;
item.Table_Id = tableInfo.Table_Id;
addColumns.Add(item);
continue;
}
//修改了数据类库或字段长度
if (item.ColumnType != tableColumn.ColumnType || item.Maxlength != tableColumn.Maxlength || (item.IsNull ?? 0) != (tableColumn.IsNull ?? 0))
{
tableColumn.ColumnType = item.ColumnType;
tableColumn.Maxlength = item.Maxlength;
tableColumn.IsNull = item.IsNull;
updateColumns.Add(tableColumn);
}
}
//删除的列
List delColumns = detailList.Where(a => !columns.Select(c => c.ColumnName).Contains(a.ColumnName)).ToList();
if (addColumns.Count + delColumns.Count + updateColumns.Count == 0)
{
return webResponse.Error("【" + tableName + "】表结构未发生变化");
}
repository.AddRange(addColumns);
repository.DbContext.Set().RemoveRange(delColumns);
repository.UpdateRange(updateColumns, x => new { x.ColumnType, x.Maxlength, x.IsNull });
await repository.DbContext.SaveChangesAsync();
return webResponse.OK($"新加字段【{addColumns.Count}】个,删除字段【{delColumns.Count}】,修改字段【{updateColumns.Count}】");
}
///
/// 生成Services/Repository与对应的Partial类
///
///
///
///
///
///
///
public string CreateServices(string tableName, string nameSpace, string foldername, bool webController, bool apiController)
{
var tableColumn = repository.FindAsyncFirst(x => x.TableName == tableName).Result;
if (tableColumn == null)
{
return $"没有查到{tableName}表信息";
}
if (string.IsNullOrEmpty(nameSpace) || string.IsNullOrEmpty(foldername))
{
return $"命名空间、项目文件夹都不能为空";
}
string domainContent = "";
string frameworkFolder = ProjectPath.GetProjectDirectoryInfo()?.FullName;
string[] splitArr = nameSpace.Split('.');
string projectName = splitArr.Length > 1 ? splitArr[splitArr.Length - 1] : splitArr[0];
string baseOptions = "\"" + projectName + "\"," + "\"" + foldername + "\"," + "\"" + tableName + "\"";
if (apiController)
{
string apiPath = ProjectPath.GetProjectDirectoryInfo().GetDirectories().Where(x => x.Name.ToLower().EndsWith("_webapi")).FirstOrDefault()?.FullName;
if (string.IsNullOrEmpty(apiPath))
{
return "未找到webapi类库,请确认是存在_webapi类库命名以_webapi结尾";
}
apiPath += $"\\Controllers\\{projectName}\\";
//生成Partial Api控制器
if (!FileHelper.FileExists($"{apiPath}Partial\\{tableName}Controller.cs"))
{
string partialController = FileHelper.ReadFile(@"Template\\Controller\\ControllerApiPartial.html")
.Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{StartName}", StratName);
FileHelper.WriteFile($"{apiPath}Partial\\", tableName + "Controller.cs", partialController);
}
//生成Api控制器
domainContent = FileHelper.ReadFile(@"Template\\Controller\\ControllerApi.html")
.Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{StartName}", StratName).Replace("{BaseOptions}", baseOptions);
FileHelper.WriteFile(apiPath, tableName + "Controller.cs", domainContent);
}
//生成Repository类
domainContent = FileHelper.ReadFile("Template\\Repositorys\\BaseRepository.html").Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{StartName}", StratName);
FileHelper.WriteFile(
frameworkFolder + string.Format("\\{0}\\Repositories\\{1}\\", nameSpace, foldername)
, tableName + "Repository.cs", domainContent);
//生成IRepository类
domainContent = FileHelper.ReadFile("Template\\IRepositorys\\BaseIRepositorie.html").Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{StartName}", StratName);
FileHelper.WriteFile(
frameworkFolder + string.Format("\\{0}\\IRepositories\\{1}\\", nameSpace, foldername),
"I" + tableName + "Repository.cs", domainContent);
string path = $"{frameworkFolder}\\{nameSpace}\\IServices\\{foldername}\\";
string fileName = "I" + tableName + "Service.cs";
//生成Partial IService类
if (!FileHelper.FileExists(path + "Partial\\" + fileName))
{
domainContent = FileHelper.ReadFile("Template\\IServices\\IServiceBasePartial.html").Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{StartName}", StratName);
FileHelper.WriteFile(path + "Partial\\", fileName, domainContent);
}
//生成IService类
domainContent = FileHelper.ReadFile("Template\\IServices\\IServiceBase.html").Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{StartName}", StratName);
FileHelper.WriteFile(path, fileName, domainContent);
path = $"{frameworkFolder}\\{nameSpace}\\Services\\{foldername}\\";
fileName = tableName + "Service.cs";
//生成Partial Service类
domainContent = FileHelper.ReadFile("Template\\Services\\ServiceBasePartial.html").Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{StartName}", StratName);
if (!FileHelper.FileExists(path + "Partial\\" + fileName))
{
domainContent = FileHelper.ReadFile("Template\\Services\\ServiceBasePartial.html").Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{StartName}", StratName);
FileHelper.WriteFile(path + "Partial\\", fileName, domainContent);
}
//生成Service类
domainContent = FileHelper.ReadFile("Template\\Services\\ServiceBase.html")
.Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName)
.Replace("{StartName}", StratName);
FileHelper.WriteFile(path, fileName, domainContent);
if (webController)
{
path = $"{frameworkFolder}\\{nameSpace}\\Controllers\\{foldername}\\";
fileName = tableName + "Controller.cs";
//生成Partial web控制器
if (!FileHelper.FileExists(path + "Partial\\" + fileName))
{
domainContent = FileHelper.ReadFile("Template\\Controller\\ControllerPartial.html").Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{BaseOptions}", baseOptions).Replace("{StartName}", StratName);
FileHelper.WriteFile(path + "Partial\\", tableName + "Controller.cs", domainContent);
}
//生成web控制器
domainContent = FileHelper.ReadFile("Template\\Controller\\Controller.html").Replace("{Namespace}", nameSpace).Replace("{TableName}", tableName).Replace("{BaseOptions}", baseOptions).Replace("{StartName}", StratName);
FileHelper.WriteFile(path, tableName + "Controller.cs", domainContent);
}
return "业务类创建成功!";
}
///
/// 获取界面查询字段
///
///
///
///
///
///
private List