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; } } } }