博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用Visual Studio宏来自动生成代码 [ Visual Studio | 宏 | 自动生成代码 ]
阅读量:5989 次
发布时间:2019-06-20

本文共 11317 字,大约阅读时间需要 37 分钟。

前言

      宏的定义:是组合到一起形成一个命令以自动完成某项任务的一系列命令和指令。(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,如需转载请自行联系原作者

你可能感兴趣的文章
MyEclipse2015整合SSM框架:详解Mybatis逆向工程配置一对一关联表,查询结果排序问题...
查看>>
如何写出漂亮的 React 组件
查看>>
机器视觉与钢铁产业条形码追溯
查看>>
Android汉字转拼音HanziToPinyin
查看>>
Java语言中:float数据类型在内存中是怎么存储的?
查看>>
04.LoT.UI 前后台通用框架分解系列之——轻巧的弹出框
查看>>
研究人员发明可穿戴型弹性光纤,可精准测量到人们的每一次呼吸
查看>>
如何通过idea连接mysql实现简单的CRUD
查看>>
孔晓泉:自然语言处理应用和前沿技术回顾 | 分享总结
查看>>
胡振波:我的芯片之路
查看>>
Java基础-一个java文件多个类的问题
查看>>
「深度」国内云服务格局初定但机会犹在,中小玩家的空间更多在“特色云”...
查看>>
你应该这个姿势学习PHP(4)
查看>>
华为联手阿里移动推出全球首个导航产品
查看>>
亚马逊防劫机专利“新鲜出炉”,无人机送货不再是问题
查看>>
从千奇百怪的相变现象说起
查看>>
EMR Druid 探索(一)
查看>>
大朋头盔:低延迟造就逼真的虚拟现实体验
查看>>
解读 V8 GC Log(一): Node.js 应用背景与 GC 基础知识
查看>>
包含Html文件的几种方法
查看>>