使用Visual Studio宏来自动生成代码 [ Visual Studio | 宏 | 自动生成代码 ]

简介:

前言

      宏的定义:是组合到一起形成一个命令以自动完成某项任务的一系列命令和指令。(MSDN)

      在使用Visual Studio宏实现JS折叠功能的时候就想过用它来实现代码自动生成,有了前面的基础,实现起来就不那么困难了,本文将实现根据表名自动生成相关字段属性的Model代码。

 

正文

      一、预备

            1.1      关于宏的新建以及简单用法,请参见这里

            1.2      环境 Microsoft Visual Studio 2008、Microsoft SQL Server 2000

 

      二、目的

            根据类名(类名和表名须一致)自动生成列名、字段说明、属性(Properties)、构造函数。

 

      三、实现步骤

            3.1      准备测试用表结构 

if   exists  ( select   *   from  dbo.sysobjects  where  id  =   object_id (N ' [dbo].[User] ' and   OBJECTPROPERTY (id, N ' IsUserTable ' =   1 )
drop   table   [ dbo ] . [ User ]
GO

CREATE   TABLE   [ dbo ] . [ User ]  (
    
[ UniqueID ]   [ int ]   IDENTITY  ( 1 1 NOT   NULL  ,
    
[ Username ]   [ varchar ]  ( 20 ) COLLATE Chinese_PRC_CI_AS  NULL  ,
    
[ Password ]   [ varchar ]  ( 20 ) COLLATE Chinese_PRC_CI_AS  NULL  ,
    
[ Name ]   [ char ]  ( 10 ) COLLATE Chinese_PRC_CI_AS  NULL  ,
    
[ UserPermission_Id ]   [ int ]   NULL  
ON   [ PRIMARY ]
GO

ALTER   TABLE   [ dbo ] . [ User ]   ADD  
    
CONSTRAINT   [ PK_Users ]   PRIMARY   KEY    CLUSTERED  
    (
        
[ UniqueID ]
    )  
ON   [ PRIMARY ]  
GO

exec  sp_addextendedproperty N ' MS_Description ' , N ' 姓名 ' , N ' user ' , N ' dbo ' , N ' table ' , N ' User ' , N ' column ' , N ' Name '
GO
exec  sp_addextendedproperty N ' MS_Description ' , N ' 密码 ' , N ' user ' , N ' dbo ' , N ' table ' , N ' User ' , N ' column ' , N ' Password '
GO
exec  sp_addextendedproperty N ' MS_Description ' , N ' 用户名 ' , N ' user ' , N ' dbo ' , N ' table ' , N ' User ' , N ' column ' , N ' Username '
GO
exec  sp_addextendedproperty N ' MS_Description ' , N ' 用户权限 ' , N ' user ' , N ' dbo ' , N ' table ' , N ' User ' , N ' column ' , N ' UserPermission_Id '

GO

            3.2      准备获取表结构帮助类(C#)

                  3.2.1      新建项目 -> 类库,项目名称:SqlSchemaProvider

                  2.2.2      数据传输类ColumnInfo.cs 

using  System;
using  System.Collections.Generic;
using  System.Text;

///   <summary>
///  字段信息
///   </summary>
public   sealed   class  ColumnInfo
{
    
#region  Member Variable

    
private   string  name;
    
private   string  desc;
    
private   string  type;

    
#endregion

    
#region  Constructor

    
public  ColumnInfo( string  name,  string  type,  string  desc)
    {
        
this .name  =  name;
        
this .desc  =  desc;
        
this .type  =  type;
    }

    
#endregion

    
#region  Properties

    
///   <summary>
    
///  列名
    
///   </summary>
     public   string  Name
    {
        
get  {  return  name; }
        
set  { name  =  value; }
    }

    
///   <summary>
    
///  列说明
    
///   </summary>
     public   string  Description
    {
        
get  {  return  desc; }
        
set  { desc  =  value; }
    }

    
///   <summary>
    
///  数据类型(已经转换为C#)
    
///   </summary>
     public   string  Type
    {
        
get  {  return  type; }
        
set  { type  =  value; }
    }

    
#endregion

}

                  2.2.3      元数据获取帮助类SqlSchemaProvider.cs ,注意这里使用了SqlHelper.cs!
 

// ==============================================================================
//
//  作 者:农民伯伯
//  邮 箱:over140@gmail.com
//  博 客: http://over140.cnblogs.com/
//  时 间:2009-6-24
//  描 述:获取SQL SERVER 元数据
//
// ==============================================================================


using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.Data;
using  System.Data.SqlClient;

public   sealed   class  SqlSchemaProvider
{

    
#region  GetTableColumns

    
public  ColumnInfo[] GetTableColumns( string  connectstring,  string  tableName)
    {
        List
< ColumnInfo >  result  =   new  List < ColumnInfo > ();

        SqlConnectionStringBuilder scsb 
=   new  SqlConnectionStringBuilder(connectstring);
        
using  (SqlDataReader reader  =  SqlHelper.ExecuteReader(scsb.ConnectionString, CommandType.Text, SQL2000_GetTableColumns,
            
new  SqlParameter( " @DatabaseName " , scsb.InitialCatalog),
            
new  SqlParameter( " @SchemaName " " dbo " ),
            
new  SqlParameter( " @TableName " , tableName)))
        {
            
while  (reader.Read())
            {
                result.Add(
new  ColumnInfo(reader.GetString( 0 ), GetCSharpType(reader.GetString( 1 )), reader.GetString( 17 )));
            }
        }
        
return  result.ToArray();
    }

    
#region  Type Maps

    
private   string  GetCSharpType( string  type)
    {
        
if  ( string .IsNullOrEmpty(type))
            
return   " string " ;

        
string  reval  =   string .Empty;
        
switch  (type.ToLower())
        {
            
case   " varchar " :
            
case   " nchar " :
            
case   " ntext " :
            
case   " text " :
            
case   " char " :
            
case   " nvarchar " :
                reval 
=   " string " ;
                
break ;
            
case   " int " :
                reval 
=   " int " ;
                
break ;
            
case   " smallint " :
                reval 
=   " Int16 " ;
                
break ;
            
case   " bigint " :
                reval 
=   " Int64 " ;
                
break ;
            
case   " float " :
                reval 
=   " double " ;
                
break ;
            
case   " bit " :
                reval 
=   " bool " ;
                
break ;
            
case   " decimal " :
            
case   " smallmoney " :
            
case   " money " :
            
case   " numeric " :
                reval 
=   " decimal " ;
                
break ;
            
case   " binary " :
                reval 
=   " System.Byte[] " ;
                
break ;
            
case   " real " :
                reval 
=   " System.Single " ;
                
break ;
            
case   " datetime " :
            
case   " smalldatetime " :
            
case   " timestamp " :
                reval 
=   " System.DateTime " ;
                
break ;
            
case   " tinyint " :
                reval 
=   " System.Byte " ;
                
break ;
            
case   " uniqueidentifier " :
                reval 
=   " System.Guid " ;
                
break ;
            
case   " image " :
            
case   " varbinary " :
                reval 
=   " System.Byte[] " ;
                
break ;
            
case   " Variant " :
                reval 
=   " Object " ;
                
break ;
            
            
default :
                reval 
=   " string " ;
                
break ;
        }
        
return  reval;
    } 

    
#endregion

    
#endregion

    
#region  SQL Templates

    
#region  GetTableColumns

    
private   const   string  SQL2000_GetTableColumns  =   @"
              SELECT
                clmns.[name] AS [Name],
                usrt.[name] AS [DataType],
                ISNULL(baset.[name], N'') AS [SystemType],
                CAST(CASE WHEN baset.[name] IN (N'char', N'varchar', N'binary', N'varbinary', N'nchar', N'nvarchar') THEN clmns.prec ELSE clmns.length END AS INT) AS [Length],
                CAST(clmns.xprec AS TINYINT) AS [NumericPrecision],
                CAST(clmns.xscale AS INT) AS [NumericScale],
                CASE CAST(clmns.isnullable AS BIT) WHEN 1 THEN 'YES' ELSE 'NO' END AS [Nullable],
                defaults.text AS [DefaultValue],
                CAST(COLUMNPROPERTY(clmns.id, clmns.[name], N'IsIdentity') AS INT) AS [Identity],
                CAST(COLUMNPROPERTY(clmns.id, clmns.[name], N'IsRowGuidCol') AS INT) AS IsRowGuid,
                CAST(COLUMNPROPERTY(clmns.id, clmns.[name], N'IsComputed') AS INT) AS IsComputed,
                CAST(COLUMNPROPERTY(clmns.id, clmns.[name], N'IsDeterministic') AS INT) AS IsDeterministic,
                CAST(CASE COLUMNPROPERTY(clmns.id, clmns.[name], N'IsIdentity') WHEN 1 THEN IDENT_SEED(QUOTENAME(stbl.[name]) + '.' + QUOTENAME(tbl.[name])) ELSE 0 END AS NVARCHAR(40)) AS [IdentitySeed],
                CAST(CASE COLUMNPROPERTY(clmns.id, clmns.[name], N'IsIdentity') WHEN 1 THEN IDENT_INCR(QUOTENAME(stbl.[name]) + '.' + QUOTENAME(tbl.[name])) ELSE 0 END AS NVARCHAR(40)) AS [IdentityIncrement],
                cdef.[text] AS ComputedDefinition,
                clmns.[collation] AS Collation,
                CAST(clmns.colid AS int) AS ObjectId,
        isnull(prop.value, '') AS ColumnDesc
              FROM
                dbo.sysobjects AS tbl
                INNER JOIN dbo.sysusers AS stbl ON stbl.[uid] = tbl.[uid]
                INNER JOIN dbo.syscolumns AS clmns ON clmns.id=tbl.id
                LEFT JOIN dbo.systypes AS usrt ON usrt.xusertype = clmns.xusertype
                LEFT JOIN dbo.sysusers AS sclmns ON sclmns.uid = usrt.uid
                LEFT JOIN dbo.systypes AS baset ON baset.xusertype = clmns.xtype and baset.xusertype = baset.xtype
                LEFT JOIN dbo.syscomments AS defaults ON defaults.id = clmns.cdefault
                LEFT JOIN dbo.syscomments AS cdef ON cdef.id = clmns.id AND cdef.number = clmns.colid
        LEFT OUTER JOIN sysproperties prop ON clmns.id = prop.id AND clmns.colid = prop.smallid 
              WHERE
                (tbl.[type] = 'U' OR tbl.[type] = 'S') 
                AND stbl.[name] = 'dbo'
                AND tbl.[name] = 
@TableName
              ORDER BY
                  clmns.colorder
" ;

    
#endregion

    
#endregion

}

            3.3      宏中引用帮助类

                  3.3.1      由于不能直接用绝对路径添加dll,所以需要将SqlSchemaProvider.dll拷贝到<安装目录>\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies

                  3.3.2      引用System.Data.dll和SqlSchemaProvider.dll

 

 

    3.4      编写宏代码

Imports  System
Imports  EnvDTE
Imports  EnvDTE80
Imports  EnvDTE90
Imports  System.Diagnostics
Imports  System.Collections.Generic

' ============================================================================
'
'
 作 者:农民伯伯
'
 邮 箱:over140@gmail.com
'
 博 客:http://over140.cnblogs.com/
'
 时 间:2009-6-24
'
 描 述:自动生成Model宏
'
'
============================================================================
Public   Module  AutoModel

    
Dim  selection  As  EnvDTE.TextSelection

    
Sub  GenerateModel()
        
Dim  schemaProvide  As  SqlSchemaProvider  =   New  SqlSchemaProvider()
        
Const  ConnStr  As   String   =   " Data Source=.;Initial Catalog=DBName;User ID=sa;Password=sa; "
        
Dim  tableName  As   String
        
Dim  columns()  As  ColumnInfo          ' 用于存放字段信息
         Dim  line  As   Integer

        selection 
=  DTE.ActiveDocument.Selection
        tableName 
=  selection.Text

        
' ------------------------------------------------------验证
         If   String .IsNullOrEmpty(tableName)  Then
            
MsgBox ( " 请选择要表名! " , MsgBoxStyle.OkOnly)
            
Return
        
End   If

        
' 取得所有字段
        columns  =  schemaProvide.GetTableColumns(ConnStr, tableName)

        
If  columns.Length  =   0   Then
            
MsgBox ( " 表不存在或该表没有字段! " , MsgBoxStyle.OkOnly)
            
Return
        
End   If

        
' 移动当前行位置,添加占位行
        line  =  selection.ActivePoint.Line  +   2
        selection.GotoLine(line)
        selection.NewLine(columns.Length 
*   2 )
        selection.GotoLine(line)

        
' ------------------------------------------------------成员变量
        NewLineInsert( " #region Member Variable " )
        selection.NewLine(
2 )

        
For   Each  column  As  ColumnInfo  In  columns

            InsertNewLine(
String .Format( " private {0} {1}; " , column.Type, column.Name.ToLower()))

        
Next

        NewLineInsert(
" #endregion " )
        selection.NewLine()

        
' ------------------------------------------------------构造函数
        NewLineInsert( " #region Constructor " )
        selection.NewLine()

        NewLineInsert(
String .Format( " public {0}() " , tableName))
        NewLineInsert(
" { " )
        NewLineInsert(
" } " )

        NewLineInsert(
" #endregion " )
        selection.NewLine()

        
' ------------------------------------------------------字段
        NewLineInsert( " #region 字段名称 " )
        selection.NewLine(
2 )

        
For   Each  column  As  ColumnInfo  In  columns

            InsertNewLine(
" /// <summary> " )
            
If  ( String .IsNullOrEmpty(column.Description))  Then
                InsertNewLine(
" 没有字段说明 " )
            
Else
                InsertNewLine(column.Description)
            
End   If
            InsertNewLine(
" </summary> " )
            selection.GotoLine(selection.AnchorPoint.Line)
            selection.SelectLine()

            InsertNewLine(
String .Format( " public const string CN_{0} = ""{0}""; " , column.Name))
            selection.NewLine()

        
Next

        InsertNewLine(
" #endregion " )

        
' ------------------------------------------------------属性(Properties)
        NewLineInsert( " #region Properties " )
        selection.NewLine(
2 )

        
For   Each  column  As  ColumnInfo  In  columns

            InsertNewLine(
" /// <summary> " )
            
If  ( String .IsNullOrEmpty(column.Description))  Then
                InsertNewLine(
" 没有字段说明 " )
            
Else
                InsertNewLine(column.Description)
            
End   If
            InsertNewLine(
" </summary> " )
            selection.GotoLine(selection.AnchorPoint.Line)
            selection.SelectLine()

            InsertNewLine(
String .Format( " public {0} {1} " , column.Type, System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(column.Name)))
            InsertNewLine(
" { " )
            InsertNewLine(
String .Concat( " get { return  " , column.Name.ToLower(),  " ; } " ))
            InsertNewLine(
String .Concat( " set {  " , column.Name.ToLower(),  "  = value; } " ))
            InsertNewLine(
" } " )
            selection.NewLine()

        
Next

        NewLineInsert(
" #endregion " )
        selection.NewLine()

        
' 格式化文档 
         ' DTE.ExecuteCommand("Edit.FormatDocument")
        DTE.ExecuteCommand( " 编辑.设置文档的格式 " )
        
' 折叠代码
        DTE.ExecuteCommand( " 编辑.折叠到定义 " )

    
End Sub

    
Sub  NewLineInsert( ByVal  code  As   String )
        
' 相当于在编辑器内按Enter键
        selection.NewLine()
        selection.Insert(code)
    
End Sub

    
Sub  InsertNewLine( ByVal  code  As   String )
        selection.Insert(code)
        selection.NewLine()
    
End Sub

End Module

                  代码说明:

                        a).      如果不熟悉VBA编程建议尽量将逻辑代码、访问数据库代码用C#写成类库再引用进来调用。

                        b).      注意连接数据库字符串ConnStr需要替换成自己的数据库连接字符串!

                        c).      输出代码的排版并不全是简单的一行输出一个字串就行了,需要模拟你在编辑器中输入代码的同时VS自动生成的代码,比如在一个属性(Property)上行输入"///"他就会自动给你生成注释,如果你在后面的行还输出"/// 说明"那就会出错了,格式也乱了,所以需要特别注意!

                        d).      宏最后有"DTE.ExecuteCommand("编辑.设置文档的格式")"这样的代码,这个用于直接调用工具栏里面功能,这里写英文的行,写中文的也行:)

            3.5      设置运行宏

                  3.5.1      设置宏快捷键(参照前文),这里设置为Ctrl+G、Ctrl+M

                  3.5.2      新建类User,注意类名和表名须一致

     class  User
    {

    }

                   3.5.3      选中类名User,快捷键Ctrl+G、Ctrl+M运行宏,生成如下:

 

 

展开部分代码

 

 

结束语

      曾做过一次对日外包的项目,印象最深的是他们Excel用得非常好,用来写式样书、写测试报告,用Excel中的宏来生成数据库、生成测试数据等复杂的操作,非常强悍,至此也算小小的满足了一下羡慕的心理: )



本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/584225,如需转载请自行联系原作者

相关文章
|
开发工具 git C++
『实用教程』使用Visual Studio自带的Git管理回滚代码版本
使用Visual Studio自带的Git管理回滚代码版本
1207 0
『实用教程』使用Visual Studio自带的Git管理回滚代码版本
|
4月前
|
Ubuntu Linux 开发工具
Linux操作系统Ubuntu 22.04配置Visual Studio Code与C++代码开发环境的方法
Linux操作系统Ubuntu 22.04配置Visual Studio Code与C++代码开发环境的方法
119 0
|
6月前
|
IDE 开发工具
如何使用 Visual Studio Code 查看和浏览 ABAP 代码试读版
如何使用 Visual Studio Code 查看和浏览 ABAP 代码试读版
48 0
|
8月前
|
C++
Visual Studio 2019 实用功能设置(背景颜色,代码字体及行号设置)
Visual Studio 2019 安装包的下载教程、安装教程 教程第一篇:Visual Studio 2019 详细安装教程(图文版) 第二篇:Visual Studio 2019 实用功能设置(背景颜色,代码颜色及行号设置) 第三篇:Visual Studio 2019 代码调试技巧 第四篇:Visual Studio 2019 解决scanf 警告问题
265 0
|
9月前
Visual Studio(管理代码工具)如何使用
1.连接到远程仓库 2.找到对应的代码库克隆到本地 3.选分支
|
人工智能 前端开发 JavaScript
提高Java开发效率:5个常用的Visual Studio代码扩展工具
对于软件工程师来说,能够更好地管理时间是一项宝贵的技能。因此,这里有5个Visual Studio代码扩展工具,可以帮助前端开发人员(以及更多的人!)将生产力至少提高10%到20%,下面和小编一起来看看吧!
188 0
提高Java开发效率:5个常用的Visual Studio代码扩展工具
|
存储 JSON JavaScript
简说Visual Studio代码进行调试
前端编程很有趣,开发人员有能力创建他们想要的任何东西,任何效果。不幸的是,当遇到bug时,这种乐趣就会消失。JavaScript开发人员可能首先想到的是alert、console.log语句。添加console.log()是可视化代码状态的一种快速方法。
260 0
简说Visual Studio代码进行调试
|
存储 API 云计算
微软行星云计算Planetary Computer——使用 Visual Studio 代码
微软行星云计算Planetary Computer——使用 Visual Studio 代码
177 0
微软行星云计算Planetary Computer——使用 Visual Studio 代码
|
存储 开发工具 git
10分钟教你用Visual Studio 2017将代码上传到GitHub(二)
10分钟教你用Visual Studio 2017将代码上传到GitHub
282 0
10分钟教你用Visual Studio 2017将代码上传到GitHub(二)
|
存储 IDE 开发工具
10分钟教你用Visual Studio 2017将代码上传到GitHub(一)
10分钟教你用Visual Studio 2017将代码上传到GitHub
900 0
10分钟教你用Visual Studio 2017将代码上传到GitHub(一)

热门文章

最新文章