使用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中的宏来生成数据库、生成测试数据等复杂的操作,非常强悍,至此也算小小的满足了一下羡慕的心理: )

转载:http://www.cnblogs.com/over140/archive/2009/06/25/1510162.html

时间: 2024-09-20 18:36:24

使用Visual Studio宏来自动生成代码 [ Visual Studio | 宏 | 自动生成代码 ]的相关文章

用c#写代码-Visual Studio中用C#编写相关程序

问题描述 Visual Studio中用C#编写相关程序 在Visual Studio中用C#编写奇数的累加和,我的代码写出来了但是不能运行,请各位帮忙看一下哪里出错了: int number, i, sum; sum = 0; number = Convert.ToInt(txtNumber.Text); for(i=1;i<=number;i=i+2) {sum=sum+i;} lblResult.Text = Convert.ToString(sum); 解决方案 int number =

【明星自动大变脸】最新StarGAN对抗生成网络实现多领域图像变换(附代码)

图像到图像转化的任务是将一个给定图像的特定方面改变到另一个方面,例如,将一个人的面部表情从微笑到皱眉改变(见图1).自从生成对抗网络(GANs)的引入,这个任务经历了很大的发展,从改变发色,改变边缘图以重建照片,到改变风景图像的季节等. 图1. 通过从RaFD数据集学习转移知识,从而应用到CelebA图像转化的多域的图像到图像转化结果.第一列和第六列显示输入图像,其余列是产生的StarGAN图像.注意,图像是由一个单一模型网络生成的,面部表情标签如生气.高兴.恐惧是从RaFD学习的,而不是来自C

编辑器-如何让kindeditor4切换到“HTML代码”模式下不自动格式化HTML标记属性

问题描述 如何让kindeditor4切换到"HTML代码"模式下不自动格式化HTML标记属性 如这样: <li {if:[list:i]=1} class=""cur""{end if}>会自动变成:<li {if:[list:i]=""1}"" class=""cur"" {end="""" if}=&qu

php 生成静态页面的办法与实现代码详细版_php实例

php中主要用到的就是要用到fread()和fwirte().而静态页面生成了之后,就会牵扯到修改的问题.这里可以用到正则匹配的方法来替换模版中改变的部位.不过此种方法太麻烦,值得推荐的方法是直接把原来生成的模版砍掉,重新生成,呵呵,真正的一了百了. 还需要说明的一点就是,这种生成静态页面的方法一般都用于那些变化不是很频繁的页面,比如信息的最终页面.而针对列表页,如果信息更新不是很频繁的话,也是可取的.现在网上流行好多可以生成静态页面的blog或者论坛程序,都是通过手动点击后台"生成html页&

《Visual Basic 2012入门经典》----1.7 编写界面后面的代码

1.7 编写界面后面的代码 Visual Basic 2012入门经典为使程序能够执行操作和响应用户交互,必须为程序编写代码.Visual Basic是一款事件驱动的语言,这意味着代码将响应事件而执行.事件可能来自用户,如用户单击按钮触发其Click事件:也可能来自Windows本身(对事件的完整解释请参见第4章).目前,该应用程序看起来不错,但并不能做任何事情.用户单击Select Picture按钮直到患上腕管综合症,也不会有什么事情发生,因为没有告诉程序当用户单击按钮时要做什么.现在按F5

使用RTC构建引擎搭建静态代码检测BEAM的自动测试环境

通过自定义构建引擎和构建定义可以很方便的将各种代码测试或者编译工具集成入 RTC 自动化运行,同时也可以很便利的将测试或者编译结果上传回 RTC,供开发和测试人员查看. IBM Checking Tool for Bugs Errors and Mistakes(本文后面将采用其文字缩写 BEAM)是 IBM 开发的一个静态分析工具,用于查找 C.C + +和 Java 程序中的错误.它直接对代码进行分析,不会尝试执行源代码,也不需要对代码进行编译连接,因此并不需要为代码编写任何测试用例.它是对

asp生成utf-8静态html页面的函数代码

用asp生成静态utf-8编码网页的代码.用fso无法生成,只有使用Adodb.Stream才可以生成真正的UTF-8静态页 <%Dim sContent,iType,oAdossContent = ""iType = 2    '类型(1-二进制/2-文本)Set oAdos = Server.CreateObject("Adodb.Stream")With oAdos    .Type = iType    .Mode = 3    .CharSet =

基本技术: Visual Studio 2010中的多重目标 Visual Basic应用程序

在 Visual Studio 2008 之前,编写面向不同版本的 Microsoft .NET Framework 的应用程序需要安装不同版本的 Visual Studio 开发环境.每个版本的 Visual Studio 都提供了不同的开发人员体验,并会占用大量磁盘空间.而且,每个版本的 Visual Studio 的项目文件格式也各不相同.结果就是当您开发面向不同版本的 .NET Framework 的项目组件时,您会得到多个版本的项目文件或解决方案. Visual Studio 2008

等待指定时间后自动跳转或关闭当前页面的js代码

本文为大家详细介绍下如何通过js实现等待指定时间后自动跳转或关闭当前页面的脚步代码,感兴趣的朋友可以参考下哈,希望对大家有所帮助   复制代码 代码如下: //指定时间之后跳转 <script language="javascript"> function go( ) {//定义函数 window.location="main.html";//页面跳转 } window.setTimeout("go()",1000);//1秒后执行函