• 完美解决CodeSmith无法获取MySQL表及列Description说明注释的方案


    问题描述:

      CodeSmith是现在比较实用的代码生成器,但是我们发现一个问题:

      使用CodeSmith编写MySQL模板的时候,会发现一个问题:MySQL数据表中的列说明获取不到,也就是column.Description。如图:

    MySQL其中一张表,里面每一列都设置有说明信息

    我们打开CodeSmith编写一个简单的Model实体类的示例模板如下:

     1 <%-- 
     2 Name:           MySQL Model实体模板
     3 Author:         孤影[QQ:778078163]
     4 Description:    CodeSmith连接MySQL生成Model实体模板
     5 --%>
     6 
     7 <%@ Template Language="C#" TargetLanguage="C#" ResponseEncoding="UTF-8" %>
     8 
     9 <%@ Assembly Name="SchemaExplorer" %>
    10 <%@ Import Namespace="SchemaExplorer" %>
    11 
    12 <%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Description="目标数据表" %>
    13 <%@ Property Name="ModelNamespace" Type="System.String" Description="Model实体所在的命名空间" %>
    14 
    15 using System;
    16 using System.Collections.Generic;
    17 using System.Linq;
    18 using System.Text;
    19 namespace <%=ModelNamespace %>
    20 {
    21     /// <summary>
    22     /// <%=SourceTable.Description %>
    23     /// </summary>
    24     public class <%=SourceTable.Name %>
    25     {
    26         <%
    27             // 循环遍历 获取当前数据表中的所有列
    28             foreach(ColumnSchema column in SourceTable.Columns){
    29                 Response.WriteLine(string.Format("// {0}",column.Description));
    30                 Response.WriteLine(string.Format("public {0} {1} ;",GetCSharpVariableType(column),column.Name));
    31             }
    32         %>
    33     }
    34 }
    35 
    36 <script runat="template">
    37 // 获取指定列对应的C#数据类型
    38 public string GetCSharpVariableType(ColumnSchema column)
    39 {
    40     if (column.Name.EndsWith("TypeCode")) return column.Name;
    41     
    42     switch (column.DataType)
    43     {
    44         case DbType.AnsiString: return "string";
    45         case DbType.AnsiStringFixedLength: return "string";
    46         case DbType.Binary: return "byte[]";
    47         case DbType.Boolean: return "bool";
    48         case DbType.Byte: return "byte";
    49         case DbType.Currency: return "decimal";
    50         case DbType.Date: return "DateTime";
    51         case DbType.DateTime: return "DateTime";
    52         case DbType.Decimal: return "decimal";
    53         case DbType.Double: return "double";
    54         case DbType.Guid: return "Guid";
    55         case DbType.Int16: return "short";
    56         case DbType.Int32: return "int";
    57         case DbType.Int64: return "long";
    58         case DbType.Object: return "object";
    59         case DbType.SByte: return "sbyte";
    60         case DbType.Single: return "float";
    61         case DbType.String: return "string";
    62         case DbType.StringFixedLength: return "string";
    63         case DbType.Time: return "TimeSpan";
    64         case DbType.UInt16: return "ushort";
    65         case DbType.UInt32: return "uint";
    66         case DbType.UInt64: return "ulong";
    67         case DbType.VarNumeric: return "decimal";
    68         default:
    69         {
    70             return "__UNKNOWN__" + column.NativeType;
    71         }
    72     }
    73 }
    74 </script>
    一个简单的CodeSmith生成Model实体的模板

    然后我们点击生成,生成的代码如下图:

    表及每一列的说明都获取失败

    当然,使用SQL Server及其他数据库都是可以获取到的,这是为什么呢?

    逼的没招没招了的时候,果断打开.NET Reflector,看看CodeSmith对SQL Server和MySQL二者,数据表生成操作的时候,有什么不同的地方,或者有什么缺少的地方。

    CodeSmith中对MySQL操作的DLL组件位置是:“X:\...\CodeSmith\v7.0\SchemaProviders\SchemaExplorer.MySQLSchemaProvider.dll

    展开后,开始一个个找里面的方法,突然发现一个亮点:“GetTableColumns(string connectionString, TableSchema table);

    这个字面的意思不就是获取列数据么?打开看看。。。可惜,里面只是根据表查询所有列,并没有Description相关操作。

    继续找,继续对比。。。最终终于找到问题了:

    方法“GetExtendedProperties(string connectionString, SchemaObjectBase schemaObject);”里面的查询语句是:

    string str = string.Format("SELECT EXTRA, COLUMN_DEFAULT, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME = '{1}' AND COLUMN_NAME = '{2}'", schema.Table.Database.Name, schema.Table.Name, schema.Name);
    

    这个不就是获取Column列中的扩展属性的方法么?!

    对比发现,SQL Server的dll里这个方法的下面,有返回Description,而MySQL正好没有!

    二话不说,找到CodeSmith的源码包解压,翻出MySQL的项目:“X:\...\CodeSmith\v7.0\Samples\Samples\Projects\CSharp\MySQLSchemaProvider

    然后打开Visual Studio载入"MySQLSchemaProvider.csproj",有很多错误,那是因为缺少了引用,添加CodeSmith\bin里面的相关引用即可。

    需要引用的组件你可以在下面两个CodeSmith安装目录中找到:

    X:\...\CodeSmith\v7.0\bin\”、“X:\...\CodeSmith\v7.0\AddIns\

    添加引用之后,错误就全部没了:

    然后我们果断开始修改代码、首先找到刚刚那个获取列扩展属性的方法:

    public ExtendedProperty[] GetExtendedProperties(string connectionString, SchemaObjectBase schemaObject)

    然后我们根据观察SQL Server的代码,发现MySQL里面这个方法:

    在SQL语句查询的时候少查询了一项数据:“COLUMN_COMMENT”,于是我们首先修改它查询的SQL语句如下:

    string commandText = string.Format(@"SELECT EXTRA, COLUMN_DEFAULT, COLUMN_TYPE, COLUMN_COMMENT
                                                          FROM INFORMATION_SCHEMA.COLUMNS
                                                          WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME = '{1}' AND COLUMN_NAME = '{2}'",
                                                          columnSchema.Table.Database.Name, columnSchema.Table.Name, columnSchema.Name);

    既然上面查询了,按照正常的数据查询流程,下面应该遍历读取,然后返回吧?

    于是继续看,下面有一个while,正是将上面查询出来的数据返回的,我们对比SQL Server的代码发现:

    上面查询出来的每一项,下面都有获取返回,而我们刚刚添加的那个“COLUMN_COMMENT”则没有进行数据获取、没有怎么办?加呗~

    获取每个数据后,最后统一将封装在“extendedProperties”中,于是我们也将获取到的Description添加进去,其与步骤省略。最终修改的代码如下:

     1 public ExtendedProperty[] GetExtendedProperties(string connectionString, SchemaObjectBase schemaObject)
     2         {
     3             List<ExtendedProperty> extendedProperties = new List<ExtendedProperty>();
     4 
     5             if (schemaObject is ColumnSchema)
     6             {
     7                 ColumnSchema columnSchema = schemaObject as ColumnSchema;
     8 
     9                 string commandText = string.Format(@"SELECT EXTRA, COLUMN_DEFAULT, COLUMN_TYPE, COLUMN_COMMENT
    10                                                       FROM INFORMATION_SCHEMA.COLUMNS
    11                                                       WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME = '{1}' AND COLUMN_NAME = '{2}'",
    12                                                       columnSchema.Table.Database.Name, columnSchema.Table.Name, columnSchema.Name);
    13 
    14                 using (DbConnection connection = CreateConnection(connectionString))
    15                 {
    16                     connection.Open();
    17 
    18                     DbCommand command = connection.CreateCommand();
    19                     command.CommandText = commandText;
    20                     command.Connection = connection;
    21 
    22                     using (IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
    23                     {
    24                         while (reader.Read())
    25                         {
    26                             string extra = reader.GetString(0).ToLower();
    27                             bool columndefaultisnull = reader.IsDBNull(1);
    28                             string columndefault = "";
    29                             if (!columndefaultisnull)
    30                             {
    31                                 columndefault = reader.GetString(1).ToUpper();
    32                             }
    33                             string columntype = reader.GetString(2).ToUpper();
    34                             string columncomment = reader.GetString(3);
    35 
    36                             bool isIdentity = (extra.IndexOf("auto_increment") > -1);
    37                             extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.IsIdentity, isIdentity, columnSchema.DataType));
    38 
    39                             if (isIdentity)
    40                             {
    41                                 /*
    42                                 MySQL auto_increment doesn't work exactly like SQL Server's IDENTITY
    43                                 I believe that auto_increment is equivalent to IDENTITY(1, 1)
    44                                 However, auto_increment behaves differently from IDENTITY when used
    45                                 with multi-column primary keys.  See the MySQL Reference Manual for details.
    46                                 */
    47                                 extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.IdentitySeed, 1, columnSchema.DataType));
    48                                 extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.IdentityIncrement, 1, columnSchema.DataType));
    49                             }
    50 
    51                             extendedProperties.Add(new ExtendedProperty("CS_ColumnDefaultIsNull", columndefaultisnull, DbType.Boolean)); // Added for Backwards Compatibility.
    52                             extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.DefaultValue, columndefault, DbType.String));
    53                             extendedProperties.Add(new ExtendedProperty("CS_ColumnDefault", columndefault, DbType.String)); // Added for Backwards Compatibility.
    54                             extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.SystemType, columntype, DbType.String));
    55                             extendedProperties.Add(new ExtendedProperty("CS_ColumnType", columntype, DbType.String)); // Added for Backwards Compatibility.
    56                             extendedProperties.Add(new ExtendedProperty("CS_ColumnExtra", extra.ToUpper(), DbType.String));
    57                             extendedProperties.Add(new ExtendedProperty("CS_Description", columncomment, DbType.String));
    58                         }
    59 
    60                         if (!reader.IsClosed)
    61                             reader.Close();
    62                     }
    63 
    64                     if (connection.State != ConnectionState.Closed)
    65                         connection.Close();
    66                 }
    67             }
    68             if (schemaObject is TableSchema)
    69             {
    70                 TableSchema tableSchema = schemaObject as TableSchema;
    71                 string commandText = string.Format(@"SHOW CREATE TABLE `{0}`.`{1}`", tableSchema.Database.Name, tableSchema.Name);
    72 
    73                 using (DbConnection connection = CreateConnection(connectionString))
    74                 {
    75                     connection.Open();
    76 
    77                     DbCommand command = connection.CreateCommand();
    78                     command.CommandText = commandText;
    79                     command.Connection = connection;
    80 
    81                     using (IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
    82                     {
    83                         while (reader.Read())
    84                         {
    85                             string createtable = reader.GetString(1);
    86                             extendedProperties.Add(new ExtendedProperty("CS_CreateTableScript", createtable, DbType.String));
    87                         }
    88 
    89                         if (!reader.IsClosed)
    90                             reader.Close();
    91                     }
    92 
    93                     if (connection.State != ConnectionState.Closed)
    94                         connection.Close();
    95                 }
    96             }
    97 
    98             return extendedProperties.ToArray();
    99         }
    最终修改完成的“GetExtendedProperties”方法

    然后我们F6生成一个修改后的dll组件"SchemaExplorer.MySQLSchemaProvider.dll"。

    找到默认的dll:“X:\...\CodeSmith\v7.0\SchemaProviders\SchemaExplorer.MySQLSchemaProvider.dll”,替.....不行,还是先备份一下。。。哈哈

    然后替换。打开重启CodeSmith,再次生成。。。-_-# 我去!这是在逗我么。

    列说明全部获取成功,但是表说明却依旧获取失败!

    再次回到Visual Studio中仔细看看整个方法,最后发现。。服了。它的这个方法的判断逻辑是:

     1 public ExtendedProperty[] GetExtendedProperties(string connectionString, SchemaObjectBase schemaObject)
     2 
     3 {
     4 
     5   List<要返回的东西>......
     6 
     7   if(schemaObject 是一个 ColumnSchema)// 如果是一个列对象
     8 
     9   {
    10 
    11     // 这里面也就是我们刚刚改的,获取列说明部分的代码
    12 
    13   }
    14 
    15   if(schemaObject 是一个 TableSchema)// 完全没有注意下面的这个判断,如果是一个表对象!!!
    16 
    17   {
    18 
    19     // 这里也就是我们下面要动手脚的地方了。
    20 
    21   }
    22 
    23 }

    废话不多说。直接上这个方法最终的代码

      1         public ExtendedProperty[] GetExtendedProperties(string connectionString, SchemaObjectBase schemaObject)
      2         {
      3             List<ExtendedProperty> extendedProperties = new List<ExtendedProperty>();
      4 
      5             if (schemaObject is ColumnSchema)
      6             {
      7                 ColumnSchema columnSchema = schemaObject as ColumnSchema;
      8 
      9                 string commandText = string.Format(@"SELECT EXTRA, COLUMN_DEFAULT, COLUMN_TYPE, COLUMN_COMMENT
     10                                                       FROM INFORMATION_SCHEMA.COLUMNS
     11                                                       WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME = '{1}' AND COLUMN_NAME = '{2}'",
     12                                                       columnSchema.Table.Database.Name, columnSchema.Table.Name, columnSchema.Name);
     13 
     14                 using (DbConnection connection = CreateConnection(connectionString))
     15                 {
     16                     connection.Open();
     17 
     18                     DbCommand command = connection.CreateCommand();
     19                     command.CommandText = commandText;
     20                     command.Connection = connection;
     21 
     22                     using (IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
     23                     {
     24                         while (reader.Read())
     25                         {
     26                             string extra = reader.GetString(0).ToLower();
     27                             bool columndefaultisnull = reader.IsDBNull(1);
     28                             string columndefault = "";
     29                             if (!columndefaultisnull)
     30                             {
     31                                 columndefault = reader.GetString(1).ToUpper();
     32                             }
     33                             string columntype = reader.GetString(2).ToUpper();
     34                             string columncomment = reader.GetString(3);
     35 
     36                             bool isIdentity = (extra.IndexOf("auto_increment") > -1);
     37                             extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.IsIdentity, isIdentity, columnSchema.DataType));
     38 
     39                             if (isIdentity)
     40                             {
     41                                 /*
     42                                 MySQL auto_increment doesn't work exactly like SQL Server's IDENTITY
     43                                 I believe that auto_increment is equivalent to IDENTITY(1, 1)
     44                                 However, auto_increment behaves differently from IDENTITY when used
     45                                 with multi-column primary keys.  See the MySQL Reference Manual for details.
     46                                 */
     47                                 extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.IdentitySeed, 1, columnSchema.DataType));
     48                                 extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.IdentityIncrement, 1, columnSchema.DataType));
     49                             }
     50 
     51                             extendedProperties.Add(new ExtendedProperty("CS_ColumnDefaultIsNull", columndefaultisnull, DbType.Boolean)); // Added for Backwards Compatibility.
     52                             extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.DefaultValue, columndefault, DbType.String));
     53                             extendedProperties.Add(new ExtendedProperty("CS_ColumnDefault", columndefault, DbType.String)); // Added for Backwards Compatibility.
     54                             extendedProperties.Add(new ExtendedProperty(ExtendedPropertyNames.SystemType, columntype, DbType.String));
     55                             extendedProperties.Add(new ExtendedProperty("CS_ColumnType", columntype, DbType.String)); // Added for Backwards Compatibility.
     56                             extendedProperties.Add(new ExtendedProperty("CS_ColumnExtra", extra.ToUpper(), DbType.String));
     57                             extendedProperties.Add(new ExtendedProperty("CS_Description", columncomment, DbType.String));
     58                         }
     59 
     60                         if (!reader.IsClosed)
     61                             reader.Close();
     62                     }
     63 
     64                     if (connection.State != ConnectionState.Closed)
     65                         connection.Close();
     66                 }
     67             }
     68             if (schemaObject is TableSchema)
     69             {
     70                 TableSchema tableSchema = schemaObject as TableSchema;
     71                 string commandText = string.Format(@"SHOW CREATE TABLE `{0}`.`{1}`", tableSchema.Database.Name, tableSchema.Name);
     72 
     73                 using (DbConnection connection = CreateConnection(connectionString))
     74                 {
     75                     connection.Open();
     76 
     77                     DbCommand command = connection.CreateCommand();
     78                     command.CommandText = commandText;
     79                     command.Connection = connection;
     80 
     81                     using (IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
     82                     {
     83                         while (reader.Read())
     84                         {
     85                             string createtable = reader.GetString(1);
     86                             extendedProperties.Add(new ExtendedProperty("TS_Description", createtable, DbType.String));
     87                             int engineIndex = createtable.LastIndexOf("ENGINE");
     88                             int commentIndex = createtable.LastIndexOf("COMMENT=");
     89                             string tableDescription = reader.GetString(0);
     90                             if (commentIndex > engineIndex)
     91                             {
     92                                 tableDescription = createtable.Substring(commentIndex + 9).Replace("'", "");
     93                             }
     94                             extendedProperties.Add(new ExtendedProperty("CS_Description", tableDescription, DbType.String));
     95 
     96                         }
     97 
     98                         if (!reader.IsClosed)
     99                             reader.Close();
    100                     }
    101 
    102                     if (connection.State != ConnectionState.Closed)
    103                         connection.Close();
    104                 }
    105             }
    106 
    107             return extendedProperties.ToArray();
    108         }
    最终的“GetExtendedProperties”方法

    重新生成,替换。。。重启CodeSmith,链接MySQL生成。。。。必然果断Ok

    网上当然也有很多例子,不过都是只处理了列的说明,没有处理表的说明

    我这个处理表说明是通过截取已获得的CreateTableScript里面的数据,获取的表说明。

    码字不容易,感觉不错的话,请不要忘了点赞哦~(*^_^ *)

    【本章来自 孤影'Blog:http://www.cnblogs.com/LonelyShadow码字不容易,转载请注明出处。】

    【来自:张董'Blogs:http://www.cnblogs.com/LonelyShadow,转载请注明出处。】

    亲们。码字不容易,觉得不错的话记得点赞哦。。

  • 相关阅读:
    Caffe + Ubuntu 15.04 + CUDA 7.0 新手安装配置指南
    姚斌分布式作业一
    一个简单正则表达式引擎的实现
    学习编程的方法
    [Leetcode]012. Integer to Roman
    [Leetcode]011. Container With Most Water
    JOS lab1 part2 分析
    我的Android Studio配置
    [Leetcode]009.Palindrome Number
    [Leetcode]008.String to Integer (atoi)
  • 原文地址:https://www.cnblogs.com/geeksss/p/4147743.html
Copyright © 2020-2023  润新知