using EFCore.Sharding;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Hosting;
using MySqlConnector;
using Npgsql;
using Oracle.ManagedDataAccess.Client;
using System.Data;
using System.Data.Common;
using System.Net;
using System.Text;
namespace Net6Demo_Api.Util
{
public class CreateCodeFileHelper : ITransientDependency
{
private readonly IDbAccessor _db;
private readonly IHostEnvironment _env;
private readonly DbProviderFactory _factory;
private string _key;
public CreateCodeFileHelper(IDbAccessor db, IHostEnvironment env)
{
_db = db;
_env = env;
switch (db.DbType)
{
case DatabaseType.SqlServer: _factory = SqlClientFactory.Instance; break;
case DatabaseType.MySql: _factory = MySqlConnectorFactory.Instance; break;
case DatabaseType.PostgreSql: _factory = NpgsqlFactory.Instance; break;
case DatabaseType.Oracle: _factory = OracleClientFactory.Instance; break;
default: throw new Exception("此数据库不支持!");
}
}
private int _isCover = 0;
///
/// 生成代码文件
///
///
public void CreateCodeFile(string tableName, string controllerName, string moduleName, int isOnlyEntity = 0, int isCover = 0)
{
_isCover = isCover;
var list = GetDataTableWithSql(DbTableSqlDic[_db.DbType]).ToJson().ToObject>();
if (!string.IsNullOrEmpty(tableName)) list = list.Where(p => p.Name.ToLower() == tableName.ToLower()).ToList();
foreach (var item in list)
{
CreateEntityFile(item.Name, item.Description, controllerName, moduleName);
if (isOnlyEntity == 0)
{
CreateBusinessFile(item.Name, controllerName, moduleName);
CreateControllerFile(item.Name, controllerName, moduleName);
}
}
}
///
/// 生成实体文件
///
public void CreateEntityFile(string tableName, string tableDescription, string controllerName, string moduleName)
{
moduleName = string.IsNullOrEmpty(moduleName) ? "" : moduleName + "\\";
string path = Directory.GetParent(_env.ContentRootPath).Parent.FullName;
string pname = _env.ApplicationName;
var dbtype = _db.DbType;
var columns = GetDataTableWithSql(DbTableColumnSqlDic[dbtype], new Dictionary() { { "@tablename", tableName } }).ToJson().ToObject>();
int index = 0;
string properties = string.Empty;
string inputproperties = string.Empty;
string viewproperties = string.Empty;
foreach (var column in columns)
{
string key = string.Empty;
if (column.IsKey)
{
key = $@"
[Key, Column(Order = {index + 1})]";
_key = column.Name;
}
Type type = DbTypeToCsharpType(column.Type);
//string isNullable = column.IsNullable && type.IsValueType ? "?" : "";
string isNullable = column.IsNullable ? "?" : "";
string description = string.IsNullOrEmpty(column.Description) ? column.Name : column.Description;
properties += $@"
/// {description}{key}
public {type.Name}{isNullable} {column.Name} {{ get; set; }}
";
inputproperties += $@"
/// {description}
public {type.Name}{isNullable} {(column.Name.StartsWith("F_") ? column.Name.Substring(2) : column.Name)} {{ get; set; }}
";
viewproperties += $@"
/// {description}
public {type.Name}{isNullable} {(column.Name.StartsWith("F_") ? column.Name.Substring(2) : column.Name)} {{ get; set; }}
";
index++;
}
string entityContent = $@"
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace {pname}.Entity
{{
///
/// {tableDescription}
///
[Table(""{tableName}"")]
public class {tableName}
{{
{properties}
}}
}}";
CreateFile($@"{path}\{pname}.Entity\DataBase\{moduleName}\{tableName}.cs", entityContent);
string inputEntityContent = $@"
using {pname}.Util;
namespace {pname}.Entity
{{
///
/// {tableDescription}
///
[Map(typeof({tableName}))]
public class {controllerName}Input
{{
{inputproperties}
}}
}}";
CreateFile($@"{path}\{pname}.Entity\Input\{moduleName}\{controllerName}Input.cs", inputEntityContent);
string viewEntityContent = $@"
using {pname}.Util;
namespace {pname}.Entity
{{
///
/// {tableDescription}
///
[Map(typeof({tableName}))]
public class {controllerName}View
{{
{viewproperties}
}}
}}";
CreateFile($@"{path}\{pname}.Entity\View\{moduleName}\{controllerName}View.cs", viewEntityContent);
//数据库类型转C#类型
Type DbTypeToCsharpType(string dbTypeStr)
{
string _dbTypeStr = dbTypeStr.ToLower();
Type type = null;
if (DbTypeDic[dbtype].ContainsKey(_dbTypeStr))
type = DbTypeDic[dbtype][_dbTypeStr];
else
type = typeof(string);
return type;
}
}
///
/// 生成控制器文件
///
///
///
///
public void CreateControllerFile(string tableName, string controllerName, string moduleName)
{
moduleName = string.IsNullOrEmpty(moduleName) ? "" : moduleName + "\\";
string path = _env.ContentRootPath + "\\Controllers\\" + moduleName;
string pname = _env.ApplicationName;
string controllerContent = $@"
using AutoMapper;
using LinqKit;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using {pname}.Entity;
using {pname}.IBusiness;
namespace {pname}.Controllers
{{
public class {controllerName}Controller : BaseController
{{
private readonly I{controllerName}Business _{controllerName}Bus;
private readonly IMapper _mapper;
public {controllerName}Controller(I{controllerName}Business {controllerName}Bus, IMapper mapper)
{{
_{controllerName}Bus = {controllerName}Bus;
_mapper = mapper;
}}
///
/// 获取分页列表
///
///
///
[HttpPost]
public async Task GetDataListPage(PageInput<{controllerName}Input> input)
{{
var q = PredicateBuilder.New<{tableName}>(true);
var data = await _{controllerName}Bus.GetListPageAsync(input, q, p => p.OrderByDescending(q => q.{_key}));
return Success(""成功"", _mapper.Map>(data.Item1), data.Item2);
}}
///
/// 获取单个
///
/// 主键ID
///
[HttpGet]
public async Task GetData(int id)
{{
var data = await _{controllerName}Bus.GetEntityAsync(id);
if (data != null) return Success(""成功"", _mapper.Map<{controllerName}View>(data));
else return Error(""获取失败"");
}}
///
/// 新增
///
///
///
[HttpPost]
public async Task AddData({controllerName}Input input)
{{
{tableName} model = _mapper.Map<{tableName}>(input);
int result = await _{controllerName}Bus.InsertAsync(model);
if (result > 0) return Success(""成功"");
else return Error(""失败"");
}}
///
/// 编辑
///
///
///
[HttpPost]
public async Task EditData({controllerName}Input input)
{{
int result = 0;
var oldData = await _{controllerName}Bus.GetEntityAsync(input.{(_key.StartsWith("F_") ? _key.Substring(2) : _key)});
if (oldData != null)
{{
_mapper.Map(input, oldData);
result = await _{controllerName}Bus.UpdateAsync(oldData);
}}
if (result > 0) return Success(""成功"");
else return Error(""失败"");
}}
///
/// 删除
///
///
///
[HttpPost]
public async Task DeleteData(List ids)
{{
if (await _{controllerName}Bus.DeleteAsync(ids) > 0) return Success(""删除成功"");
else return Error(""删除失败"");
}}
}}
}}
";
CreateFile($@"{path}\{controllerName}Controller.cs", controllerContent);
}
///
/// 生成业务文件
///
///
///
///
public void CreateBusinessFile(string tableName, string controllerName, string moduleName)
{
moduleName = string.IsNullOrEmpty(moduleName) ? "" : moduleName + "\\";
string path = Directory.GetParent(_env.ContentRootPath).Parent.FullName;
string pname = _env.ApplicationName;
string iBusinessContent = $@"
using {pname}.Entity;
namespace {pname}.IBusiness
{{
public interface I{controllerName}Business : IBaseBusiness<{tableName}>
{{
}}
}}
";
CreateFile($@"{path}\{pname}.IBusiness\{moduleName}I{controllerName}Business.cs", iBusinessContent);
string businessContent = $@"
using EFCore.Sharding;
using Microsoft.Extensions.Caching.Distributed;
using {pname}.Entity;
using {pname}.IBusiness;
using {pname}.Util;
namespace {pname}.Business
{{
public class {controllerName}Business : BaseBusiness<{tableName}>, I{controllerName}Business, ITransientDependency
{{
public {controllerName}Business(IDbAccessor db, IDistributedCache cache) : base(db, cache, false)
{{
}}
}}
}}
";
CreateFile($@"{path}\{pname}.Business\{moduleName}{controllerName}Business.cs", businessContent);
}
///
/// 创建文件
///
///
///
private void CreateFile(string filepath, string content)
{
string path = filepath.Substring(0, filepath.LastIndexOf("\\"));
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
if (File.Exists(filepath) && _isCover == 1) File.Delete(filepath);
if (!File.Exists(filepath))
{
FileInfo file = new FileInfo(filepath);
using (FileStream stream = file.Create())
{
using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.Write(content);
writer.Flush();
}
}
}
}
///
/// 根据sql获取DataTable
///
///
///
///
private DataTable GetDataTableWithSql(string sql, Dictionary paras = null)
{
using (DbConnection conn = _factory.CreateConnection())
{
conn.ConnectionString = _db.ConnectionString;
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
using (DbCommand cmd = conn.CreateCommand())
{
cmd.Connection = conn;
cmd.CommandText = sql;
if (paras != null)
{
foreach (KeyValuePair kvp in paras)
{
switch (_db.DbType)
{
case DatabaseType.SqlServer: cmd.Parameters.Add(new SqlParameter(kvp.Key, kvp.Value)); break;
case DatabaseType.MySql: cmd.Parameters.Add(new MySqlParameter(kvp.Key, kvp.Value)); break;
case DatabaseType.PostgreSql: cmd.Parameters.Add(new NpgsqlParameter(kvp.Key, kvp.Value)); break;
case DatabaseType.Oracle: cmd.Parameters.Add(new OracleParameter(kvp.Key, kvp.Value)); break;
}
}
}
DbDataAdapter adapter = _factory.CreateDataAdapter();
adapter.SelectCommand = cmd;
DataSet table = new DataSet();
adapter.Fill(table);
cmd.Parameters.Clear();
return table.Tables[0];
}
}
}
///
/// 数据库类型和C#类型字典
///
private Dictionary> DbTypeDic = new Dictionary>()
{
{ DatabaseType.SqlServer,new Dictionary()
{
{ "int", typeof(Int32) },
{ "text", typeof(string) },
{ "bigint", typeof(Int64) },
{ "binary", typeof(byte[]) },
{ "bit", typeof(bool) },
{ "char", typeof(string) },
{ "date", typeof(DateTime) },
{ "datetime", typeof(DateTime) },
{ "datetime2", typeof(DateTime) },
{ "datetimeoffset", typeof(DateTimeOffset) },
{ "decimal", typeof(decimal) },
{ "float", typeof(double) },
{ "image", typeof(byte[]) },
{ "money", typeof(decimal) },
{ "nchar", typeof(string) },
{ "ntext", typeof(string) },
{ "numeric", typeof(decimal) },
{ "nvarchar", typeof(string) },
{ "real", typeof(Single) },
{ "smalldatetime", typeof(DateTime) },
{ "smallint", typeof(Int16) },
{ "smallmoney", typeof(decimal) },
{ "time", typeof(TimeSpan) },
{ "timestamp", typeof(DateTime) },
{ "tinyint", typeof(byte) },
{ "varbinary", typeof(byte[]) },
{ "varchar", typeof(string) },
{ "variant", typeof(object) },
{ "uniqueidentifier", typeof(Guid) }
}
},
{ DatabaseType.MySql,new Dictionary()
{
{ "bool",typeof(bool)},
{ "boolean",typeof(bool)},
{ "bit(1)",typeof(bool)},
{ "binary",typeof(byte[])},
{ "varbinary",typeof(byte[])},
{ "blob",typeof(byte[])},
{ "longblob",typeof(byte[])},
{ "date",typeof(DateTime)},
{ "datetime",typeof(DateTime)},
{ "timestamp",typeof(DateTime)},
{ "datetimeoffset", typeof(DateTimeOffset) },
{ "time", typeof(TimeSpan) },
{ "double",typeof(double)},
{ "smallint",typeof(Int16)},
{ "int",typeof(Int32)},
{ "bigint",typeof(Int64)},
{ "tinyint",typeof(bool)},
{ "float",typeof(float)},
{ "decimal",typeof(decimal)},
{ "numeric",typeof(decimal)},
{ "char",typeof(string)},
{ "nchar",typeof(string)},
{ "varchar",typeof(string)},
{ "nvarchar",typeof(string)},
{ "text",typeof(string)},
{ "longtext",typeof(string)}
}
},
{ DatabaseType.PostgreSql,new Dictionary()
{
{ "bool", typeof(bool) },
{ "boolean",typeof(bool)},
{ "int2", typeof(Int16) },
{ "smallint", typeof(Int16) },
{ "int4", typeof(Int32) },
{ "bigint", typeof(Int64) },
{ "int8", typeof(Int64) },
{ "integer", typeof(Int32) },
{ "float4", typeof(float) },
{ "float8", typeof(decimal) },
{ "decimal", typeof(decimal) },
{ "numeric", typeof(decimal) },
{ "money", typeof(decimal) },
{ "text", typeof(string) },
{ "varchar", typeof(string) },
{ "bpchar", typeof(string) },
{ "citext", typeof(string) },
{ "json", typeof(string) },
{ "jsonb", typeof(string) },
{ "xml", typeof(string) },
{ "bit(1)", typeof(bool) },
{ "uuid", typeof(Guid) },
{ "inet", typeof(IPAddress) },
{ "date", typeof(DateTime) },
{ "interval", typeof(TimeSpan) },
{ "timestamp", typeof(DateTime) },
{ "timestamptz", typeof(DateTime) },
{ "time", typeof(TimeSpan) },
{ "timetz", typeof(DateTimeOffset) },
{ "bytea", typeof(byte[]) },
{ "oid", typeof(uint) },
{ "xid", typeof(uint) },
{ "cid", typeof(uint) },
{ "name", typeof(string) }
}
},
{ DatabaseType.Oracle,new Dictionary()
{
{ "boolean",typeof(bool)},
{ "bfile", typeof(byte[]) },
{ "blob", typeof(byte[]) },
{ "char", typeof(string) },
{ "clob", typeof(string) },
{ "date", typeof(DateTime) },
{ "float", typeof(decimal) },
{ "integer", typeof(decimal) },
{ "long", typeof(string) },
{ "long raw", typeof(string[]) },
{ "nchar", typeof(string) },
{ "nclob", typeof(string) },
{ "number", typeof(decimal) },
{ "nvarchar2", typeof(string) },
{ "raw", typeof(byte[]) },
{ "rowid", typeof(string) },
{ "timestamp", typeof(DateTime) },
{ "unsigned integer", typeof(decimal) },
{ "varchar2", typeof(string) }
}
},
{ DatabaseType.SQLite,new Dictionary()
{
{ "tinyint", typeof(byte) },
{ "bool", typeof(bool) },
{ "boolean",typeof(bool)},
{ "int16", typeof(Int16) },
{ "smallint", typeof(Int16) },
{ "int32", typeof(Int32) },
{ "int", typeof(Int32) },
{ "int64", typeof(Int64) },
{ "integer", typeof(Int64) },
{ "text", typeof(string) },
{ "bigint", typeof(Int64) },
{ "real", typeof(double) },
{ "numeric", typeof(decimal) },
{ "decimal", typeof(decimal) },
{ "money", typeof(decimal) },
{ "currency", typeof(decimal) },
{ "date", typeof(DateTime) },
{ "smalldate", typeof(DateTime) },
{ "datetime", typeof(DateTime) },
{ "time", typeof(TimeSpan) },
{ "ntext", typeof(string) },
{ "char", typeof(string) },
{ "nchar", typeof(string) },
{ "varchar", typeof(string) },
{ "nvarchar", typeof(string) },
{ "string", typeof(string) },
{ "binary", typeof(byte[]) },
{ "blob", typeof(byte[]) },
{ "varbinary", typeof(byte[]) },
{ "image", typeof(byte[]) },
{ "general", typeof(byte[]) },
{ "datetimeoffset", typeof(DateTimeOffset) },
{ "guid", typeof(Guid) }
}
}
};
///
/// 数据库类型表sql字典
///
private Dictionary DbTableSqlDic = new Dictionary()
{
{ DatabaseType.SqlServer,
"select [Name] = a.name, [Description] = g.value from sys.tables a left join sys.extended_properties g on (a.object_id = g.major_id AND g.minor_id = 0 AND g.name= 'MS_Description')"
},
{ DatabaseType.MySql,
"SELECT TABLE_NAME as Name,table_comment as Description FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA =(select database())"
},
{ DatabaseType.Oracle,
"SELECT A.TABLE_NAME AS NAME, B.comments AS DESCRIPTION FROM USER_TABLES A, USER_TAB_COMMENTS B WHERE A.table_name = B.table_name(+)"
},
{ DatabaseType.PostgreSql,
"select relname as Name, cast(obj_description(relfilenode,'pg_class') as varchar) as Description from pg_class c where relkind = 'r' and relname not like 'pg_%' and relname not order by relname"
},
{ DatabaseType.SQLite,""},
};
///
/// 数据库类型表字段sql字典
///
private Dictionary DbTableColumnSqlDic = new Dictionary()
{
{ DatabaseType.SqlServer,
@"
select
sys.columns.name as [Name],
sys.types.name as [Type],
sys.columns.is_nullable [IsNullable],
[IsIdentity]=CONVERT(BIT, (select count(*) from sys.identity_columns where sys.identity_columns.object_id = sys.columns.object_id and sys.columns.column_id = sys.identity_columns.column_id)),
(select value from sys.extended_properties where sys.extended_properties.major_id = sys.columns.object_id and sys.extended_properties.minor_id = sys.columns.column_id and name='MS_Description') as [Description],
[IsKey] =CONVERT(bit,(case when sys.columns.name in (select b.column_name
from information_schema.table_constraints a
inner join information_schema.constraint_column_usage b
on a.constraint_name = b.constraint_name
where a.constraint_type = 'PRIMARY KEY' and a.table_name = @tablename) then 1 else 0 end))
from sys.columns, sys.tables, sys.types where sys.columns.object_id = sys.tables.object_id and sys.columns.system_type_id=sys.types.system_type_id and sys.tables.name=@tablename and sys.types.name !='sysname'
order by sys.columns.column_id asc;"
},
{ DatabaseType.MySql,
@"
select DISTINCT
a.COLUMN_NAME as Name,
a.DATA_TYPE as Type,
(a.COLUMN_KEY = 'PRI') as IsKey,
(a.IS_NULLABLE = 'YES') as IsNullable,
a.COLUMN_COMMENT as Description,
a.ORDINAL_POSITION
from information_schema.columns a
where table_name=@tableName and table_schema=(select database())
ORDER BY a.ORDINAL_POSITION;"
},
{ DatabaseType.Oracle,
@"
SELECT
A.COLUMN_NAME AS NAME,
A.DATA_TYPE AS TYPE,
NVL2(D.CONSTRAINT_TYPE,1,0) AS ISKEY,
DECODE(A.NULLABLE,'Y',1,0) AS ISNULLABLE,
B.COMMENTS AS DESCRIPTION
FROM USER_TAB_COLUMNS A, USER_COL_COMMENTS B, USER_IND_COLUMNS C, USER_CONSTRAINTS D
WHERE A.TABLE_NAME = B.TABLE_NAME(+)
AND A.COLUMN_NAME = B.COLUMN_NAME(+)
AND A.TABLE_NAME = C.TABLE_NAME(+)
AND A.COLUMN_NAME = C.COLUMN_NAME(+)
AND C.INDEX_NAME = D.INDEX_NAME(+)
AND 'P' = D.CONSTRAINT_TYPE(+)
AND A.TABLE_NAME= :tableName
ORDER BY A.COLUMN_ID;"
},
{ DatabaseType.PostgreSql,
@"
SELECT
a.attname as Name,
pg_type.typname as Type,
(SELECT count(1) from(SELECT ic.column_name as ColumnName FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING(constraint_schema, constraint_name) JOIN information_schema.columns AS ic ON ic.table_schema = tc.constraint_schema AND tc.table_name = ic.table_name AND ccu.column_name = ic.column_name
where constraint_type = 'PRIMARY KEY' and tc.table_name = @tablename) KeyA WHERE KeyA.ColumnName = a.attname)> 0 as IsKey,
a.attnotnull<> True as IsNullable,
col_description(a.attrelid, a.attnum) as Description
FROM pg_class as c,pg_attribute as a inner join pg_type on pg_type.oid = a.atttypid
where c.relname = @tablename and a.attrelid = c.oid and a.attnum > 0
order by a.attnum asc;"
}
};
///
/// 表信息
///
private class TableInfo
{
///
/// 表名
///
public string Name { get; set; }
///
/// 表描述说明
///
public string Description
{
get
{
return string.IsNullOrEmpty(_description) ? Name : _description;
}
set
{
_description = value;
}
}
private string _description { get; set; }
}
///
/// 表结构信息
///
private class TableColumn
{
///
/// 字段名
///
public string Name { get; set; }
///
/// 字段类型
///
public string Type { get; set; }
///
/// 是否为主键
///
public bool IsKey { get; set; }
///
/// 是否为空
///
public bool IsNullable { get; set; }
///
/// 字段描述说明
///
public string Description
{
get
{
return string.IsNullOrEmpty(_description) ? Name : _description;
}
set
{
_description = value;
}
}
private string _description { get; set; }
}
}
}