Roslyn+T4+EnvDTE项目完全自动化(3) ——生成c++代码

  • A+
所属分类:.NET技术
摘要

C++语法复杂,写一个示例通过T4可生成c++代码需求:数据库,生成c++增,删,改,查代码

C++语法复杂,写一个示例通过T4可生成c++代码

需求:数据库,生成c++增,删,改,查代码

  1. 数据生成c++类,包含所有字段
  2. 自动识别数据的主键Key
  3. 查询生成赋值类字段,类型转换
  4. 通过类自动生成sql的where条件
  5. 类改变一些字段值,自动生成update sql
  6. 生成所有字段打印代码
class Actor_Entry;      //数据库实体类 class Actor_UpdateEntry;//更新实体类 class Actor             //实体增,删,改,查类 { public:     bool Select(MYSQL* connect, const std::string& sql, std::vector<Actor_Entry>& out);     bool SelectAll(MYSQL* connect, std::vector<Actor_Entry>& v);     bool Update(MYSQL* connect, const Actor_UpdateEntry& set, const Actor_UpdateEntry& where, const std::string& whereSql);     bool Update(MYSQL* connect, const std::string& whereSql);     bool Insert(MYSQL* connect, Actor_UpdateEntry& v);     bool Delete(MYSQL* connect, const Actor_UpdateEntry& v); }; class Actor_Entry { public:     std::string ToString();     static Actor_Entry& New();//方便拷贝代码     short int GetKey() const;     // 数据字段,及类型映射     // 主键(自动识别主键)     short int Actor_Id;     std::string First_Name;     std::string Last_Name;     std::string Last_Update; }; //字段发生改变,自动生成sql class Actor_UpdateEntry : public Actor_Entry { public:     Actor_UpdateEntry();      static Actor_UpdateEntry& New();//方便拷贝代码     bool IsModified() const;     void ResetModified();     void Set_Actor_Id(const short int value);     bool Actor_Id_Modified;      void Set_First_Name(const std::string& value);     bool First_Name_Modified;      void Set_Last_Name(const std::string& value);     bool Last_Name_Modified;      void Set_Last_Update(const std::string& value);     bool Last_Update_Modified; }; 

  

一个数据库,不到10s生成7000+行代码

Roslyn+T4+EnvDTE项目完全自动化(3) ——生成c++代码

 实现方式:

读取表结构:

        public static IEnumerable<TABLE_SCHEMA_> GetTableSchemaEnumerable(MySqlConnectionStringBuilder builder)         {             using (var conn = GetConnection(builder))             {                 var sql =                     $"SELECT DISTINCT t.`TABLE_COMMENT`, c.* FROM information_schema.`COLUMNS` as c INNER join INFORMATION_SCHEMA.`TABLES` t on c.`TABLE_NAME`= t.`TABLE_NAME`  where c.TABLE_SCHEMA = '{builder.Database}';";                  using (var cmd = conn.CreateCommand())                 {                     cmd.CommandText = sql;                      using (var reader = cmd.ExecuteReader())                     {                         while (reader.Read())                         {                             var obj = new TABLE_SCHEMA_();                             obj.TABLE_COMMENT = reader[nameof(obj.TABLE_COMMENT)].DbCast<string>();                             obj.TABLE_NAME = reader[nameof(obj.TABLE_NAME)].DbCast<string>();                             obj.TABLE_CATALOG = reader[nameof(obj.TABLE_CATALOG)];                             obj.TABLE_SCHEMA = reader[nameof(obj.TABLE_SCHEMA)];                             obj.TABLE_NAME = reader[nameof(obj.TABLE_NAME)].DbCast<string>();                             obj.COLUMN_NAME = reader[nameof(obj.COLUMN_NAME)].DbCast<string>();                             obj.ORDINAL_POSITION = reader[nameof(obj.ORDINAL_POSITION)].DbCast<uint>();                             obj.COLUMN_DEFAULT = reader[nameof(obj.COLUMN_DEFAULT)];                             {                                 var v = reader[nameof(obj.IS_NULLABLE)];                                 obj.IS_NULLABLE = "Yes".EqualsByIgnoreCaseEx(v.DbCast<string>());                             }                             obj.DATA_TYPE = reader[nameof(obj.DATA_TYPE)].DbCast<string>();                             obj.CHARACTER_MAXIMUM_LENGTH = reader[nameof(obj.CHARACTER_MAXIMUM_LENGTH)].DbCast<long?>();                             obj.CHARACTER_OCTET_LENGTH = reader[nameof(obj.CHARACTER_OCTET_LENGTH)].DbCast<long?>();                             obj.NUMERIC_PRECISION = reader[nameof(obj.NUMERIC_PRECISION)];                             obj.NUMERIC_SCALE = reader[nameof(obj.NUMERIC_SCALE)];                             obj.DATETIME_PRECISION = reader[nameof(obj.DATETIME_PRECISION)];                             obj.CHARACTER_SET_NAME = reader[nameof(obj.CHARACTER_SET_NAME)].DbCast<string>();                             obj.COLLATION_NAME = reader[nameof(obj.COLLATION_NAME)].DbCast<string>();                             obj.COLUMN_TYPE = reader[nameof(obj.COLUMN_TYPE)].DbCast<string>();                             obj.COLUMN_KEY = reader[nameof(obj.COLUMN_KEY)].DbCast<string>();                             obj.EXTRA = reader[nameof(obj.EXTRA)];                             obj.PRIVILEGES = reader[nameof(obj.PRIVILEGES)];                             obj.COLUMN_COMMENT = reader[nameof(obj.COLUMN_COMMENT)].DbCast<string>();                             obj.GENERATION_EXPRESSION = reader[nameof(obj.GENERATION_EXPRESSION)];                             obj.SRS_ID = reader[nameof(obj.SRS_ID)];                             yield return obj;                         }                     }                 }             }         } 

用t4生成c++代码:

bool <#= className #>::Insert(MYSQL* connect, <#= tab.ClassName_UpdateEntry #>& v) {     if(!v.IsModified())     {         return false;     } 	std::string f; 	std::string values; <#+     var isOneKey = tab.Keys.Length == 1;//判断是不是单主键     foreach (var field in tab.FieldsSupported)     {         var type = field.Type;         var name = field.Name; #>     if (v.<#=field.NameModify#>)     { 	    f += " `<#=field.ColumnName#>`,"; 	    values += std::format(" '{}',", v.<#=field.Name#>);     } <#+ 	} #> <#+if(isOneKey){//自增主键,自动写入insert的生成的key#>     { 	    std::string sql = std::format("insert into `<#=tab.TabName#>` ({}) values({});", f.substr(0, f.length() - 1), values.substr(0, values.length() - 1));         int query = mysql_query(connect, sql.c_str());         // if (!query) return false;     }     {         std::string sql = "SELECT LAST_INSERT_ID() as id;";         int query = mysql_query(connect, sql.c_str());         // if (!query) return false;     } 	     auto res = mysql_use_result(connect);     if(res == nullptr) return false;      MYSQL_ROW row;     while ((row = mysql_fetch_row(res)) != nullptr)     {         v.<#=tab.Keys[0].Name#> = Columns::GetInt(row, 0);         break;     }     mysql_free_result(res); <#+}else{#> 	std::string sql = std::format("insert into `<#=tab.TabName#>` ({}) values({});", f.substr(0, f.length() - 1), values.substr(0, values.length() - 1)); 	int query = mysql_query(connect, sql.c_str()); 	if (!query) return false; <#+}#> 	return true; } 

(c++代码多年没写,有可能有误,只是为了测试T4)

Roslyn+T4+EnvDTE ,基本上可以从一种数据源生成,另一种任意格式文本格式

视频演示

 代码

提取码:ynpb