前言 數據庫
宏的定義:是組合到一塊兒造成一個命令以自動完成某項任務的一系列命令和指令。(MSDN)編程
在使用Visual Studio宏實現JS摺疊功能的時候就想過用它來實現代碼自動生成,有了前面的基礎,實現起來就不那麼困難了,本文將實現根據表名自動生成相關字段屬性的Model代碼。編輯器
正文 ide
1、預備函數
1.1 關於宏的新建以及簡單用法,請參見這裏 。工具
1.2 環境 Microsoft Visual Studio 200八、Microsoft SQL Server 2000post
2、目的測試
根據類名(類名和表名須一致)自動生成列名、字段說明、屬性(Properties)、構造函數。ui
3、實現步驟this
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
"
p_w_picpath
"
:
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中的宏來生成數據庫、生成測試數據等複雜的操做,很是強悍,至此也算小小的知足了一下羨慕的心理: )
本博Visual Studio相關文章
1. 讓Visual Studio 也支持JS代碼摺疊 —— 續 [ Visual Studio | Js | ScriptOutline | SmallOutline ]
2. Visual Studio 讓JS也支持代碼摺疊 [ Visual Studio | #region | #endregion ]
3. Visual Studio 模板 —— 自定義WebForm模板
4. 用Visual Studio 2005/2008提取EXE文件中的資源[圖片|htm|光標文件]
5. Microsoft Visual Studio 2005 快捷鍵提示
6. Visual Studio 在根目錄下運行文件系統站點 [ Visual Studio | 文件系統 | WebDev.WebServer.EXE ]