65.9K
CodeProject 正在变化。 阅读更多。
Home

GNR8 - 简单的 C# 类生成器

2008 年 7 月 10 日

CPL

8分钟阅读

viewsIcon

85863

downloadIcon

4686

从数据库表生成 1 到 n 个类

GNR8 - primary screen after tables are loaded

引言

GNR8(请原谅这个文本语音的名称,它只是突然想到)是一个简单的 C# WinForms 应用程序,它连接到 SQL Server 数据库,列出所有表,然后允许用户选择一个表来根据自定义模板生成类。

背景

我敢肯定,与其他许多类似应用程序一样,我创建这个应用程序是因为我天生懒惰:我不想一遍又一遍地创建基本上与其他处理表的类几乎相同的基本类。

我还应该指出,hdv212 最近添加了另一个代码生成器(Database Helper v 1.0.0),它的功能与我的类似,但生成的输出比我通常需要的要多,而且方式也大不相同。这丝毫不会贬低它的价值。

使用 GNR8

GNR8 分为三个独立的部分:前两部分是必需的,第三部分完全是可选的。

首先,应用程序必须连接到数据库才能列出要处理的可用表。

GNR8 - the connection dialog

请注意,所有选择都将保存下来,以便下次启动程序时使用。

执行此操作所需的代码相当直接,并且可以在互联网上免费找到各种示例;然而,以下代码将返回一个包含可用服务器的DataTable(可以在Connect.cs文件第192行找到)。

using System.Data.Sql;

DataTable servers = SqlDataSourceEnumerator.Instance.GetDataSources();

然后,我可以使用结果数据填充DropDownList并选择我想要查询的服务器。奇怪的是,并非所有可用服务器都会列出,但您可以输入感兴趣的服务器名称,如果可用,它将连接。此外,本地服务器(不总是?)不会列出,但您可以跳到实例名称,任何已连接的本地数据库都会被列出。

Initial Catalog DropDownList 由以下代码驱动:(可以在Connect.cs文件第241行找到)

using SQLDMO;

SQLServerClass server = new SQLServerClass();

这源自一个互操作程序集 SQLDMO(已提供),该程序集在建立连接后,允许我们检查服务器并列出所有可用的目录。它们被添加到集合中,该集合随后充当列表的DataSource

Collection<string> catalogs = new Collection<string>();

// Get the objects.
foreach (Database2 db in server.Databases)
{
    if (!db.SystemObject)
    {
        catalogs.Add(db.Name);
    }
}

// Add all of the found objects to the combo.
this.cboCatalog.DataSource = catalogs;

请注意,您可以输入一个已知的数据库名称而不是搜索,然后可以测试连接(这会使您停留在当前对话框),或者选择“确定”,前提是连接详细信息正确,此对话框将关闭,主对话框(如上面的初始图像所示)将被显示。

请注意,Connect 对话框默认使用集成安全性(受信任连接)。自然,如果您需要改用用户 ID 和密码,请取消选中此选项并输入所需详细信息。

回到主屏幕,暂时忽略那些平淡无奇的工具栏图标,接下来是选择一个或多个表并按“处理”按钮,这会产生以下屏幕。

GNR8 - the process dialog

您无需输入命名空间或创建者姓名;您也不需要选择输出(另存为)文件夹,因为如果未修改,将使用 EXE 文件的路径:您的选择将被保存(在应用程序config文件中)以供下次使用。

此时,按“生成”按钮,前提是找到模板文件(请参阅下文),您的类将被创建、保存并准备就绪;如果未找到,将提示您停止并创建模板文件,然后才加载屏幕。

GNR8 依赖于包含文本和标记的模板才能工作。它可以包含您所需的任何文本;GNR8 并不真正关心文件中的内容,只关心它找到的标记,这些标记将被预定义的数据(用于内置标记)或您为自定义标记提供的数据替换。

以下是提供的模板的示例,显示了模板文件中可能包含的内容。正如我所说,它可以包含您认为合适的任何文本,GNR8 会忽略任何未包含在花括号中的内容。这些是将被其他文本替换的标记。

#region Construction
/// <summary>
/// Initializes a new (no-args) instance of the {OBJECTNAME} class.
/// </summary>
public {OBJECTNAME}()
{
}

/// <summary>
/// Initializes a new instance of the {OBJECTNAME} class.
/// </summary>
public {OBJECTNAME}({CTORPARAMETERS})
{
    {CTORBODY}
}
#endregion

在此示例中,有许多默认标记,例如 {OBJECTNAME},GNR8 将用表名替换它。下面是完整列表(可从其中一个精美的工具栏按钮访问),包含标记名称和含义。虽然它们在此处是不可变的,但您可以随意修改代码以适应您的需求。

GNR8 - the default tokens non-modal dialog

程序现在解析每个选定的表,并使用可用的信息生成一个类文件。对于每个对象,都会实例化一个ProcessObjects对象(随便我,我没有想象力),它负责为表生成一个类。

我选择了最简单的路径来解析和替换我的标记。假设创建了一个有效的ProcessObject,我们就直奔主题。

internal void ProcessObject()
{
    // Sets Ctor detail and parameters.
    this.CreateConstructor();

    // Process Custom tokens first.
    this.CustomTokens();

    // Process default Tokens.
    this.DefaultTokens();

    // Save to disk.
    File.WriteAllText(this.FullPath, this.TEMPLATE, Encoding.Default);
}

这会将过程分解为逻辑和顺序单元,稍后我将介绍CustomTokens

CreateConstructor会查询表以检索用于创建构造函数的参数/签名列表的列名,并使用以下代码执行此操作,该代码返回一个填充了表信息的DataTable

OleDbDataReader oleDbDataReader = oleDbCommand.ExecuteReader(CommandBehavior.KeyInfo);
DataTable dataTable = oleDbDataReader.GetSchemaTable();

简单地遍历行和列即可提取用于构建列表的名称;我们正在寻找名称和DataType,我们通过以下方式获取:

foreach (DataRow dataRow in dataTable.Rows)
{
    // Get the name of the column.
    string name = dataRow[0].ToString();

    foreach (DataColumn dataColumn in dataTable.Columns)
    {
        // Contains the actual data type.
        string column =
            dataRow[dataColumn]
                .ToString()
                .Replace("System.", string.Empty);

        if (dataColumn.ColumnName == "DataType")
        {
            parameters += column + " " + name + ", ";
            ctor += "this." + name + " = " + name + ";" + Environment.NewLine;
        }
    }
}

整个程序的真正核心,令人恼火的是,与其余部分相比,它非常简单……

private void DefaultTokens()
{
    this.TEMPLATE =
        this.TEMPLATE
            .Replace(Template.AUTHOR, this.Creator)
            .Replace(Template.CTORBODY, this.CtorDetail)
            .Replace(Template.CTORPARAMETERS, this.CtorPrameters)
            .Replace(Template.DATECREATED, DateTime.Today.ToShortDateString())
            .Replace(Template.NAMESPACE, this.NameSpaceName)
            .Replace(Template.OBJECTNAME, this.ObjectName)
            .Replace(Template.PRIMARYKEY, this.PrimaryKey())
            .Replace(Template.PROPERTIES, CreateProperties());
}

好了;当我们实例化类时,我们将模板一次性读取为一个string(仅此而已,很容易处理),通过以下方式:

this.TEMPLATE = File.ReadAllText(templatePath);

然后,我们只需用其他文本替换标记。“Template.AUTHOR”(等)是资源string,其中包含要替换的标记的名称,而属性包含传递过来的用于替换标记的其他数据。

虽然我相信还有其他方法可以做到这一点,但我喜欢使用string.Replace来完成所有工作,并且基本上可以用一行代码完成(忽略我为了可读性将其拆分为多行的事实)。

最后,我们将文本写入处理对话框中提供的文件名。然后,对每个表重复此过程。

几乎完成了……

就是这样:这是您在创建数据库的第一次或因为业务赞助商在上线前两天说“哦,我忘了提了吗?”而必须添加表时最有可能使用的工具之一。

自定义标记:可选部分

我决定内置的功能之一是能够添加您自己的标记。您可以根据需要命名这些标记,并根据需要填充它们。它们都保存在一个 XML 文件中,并在CustomTokens中进行解析。我创建了一个辅助类来解析文件,我喜欢 XML 的一点是,它提供了无数种实现任何功能的方法。尽管如此,我现在的实现方式有效且看起来像这样:

GNR8 - the custom tokens dialog

由于这是可选功能,我将留给您自行查看和分析代码。只需说,您可以添加/编辑和删除显示在由源自 XML 数据的DataTable填充的DataGridView中的条目。

DataSet set = new DataSet();

// Read the file.
set.ReadXml(FullPath_To_XML_File);

// Make sure that the document contains some data!
if (set.Tables.Count != 0)
{
    // Get the table.
    table = set.Tables[0];
}

return table;

上面的代码展示了处理 XML 为什么如此简单。通过Helper类,将表通过static方法传递给网格。

DataGridView.DataSource = XmlHelper.Load();

虽然XmlHelper类基本上只用于处理与 GNR8 相关的键值对,但我相信它可以适应其他用途,并且您可以随意这样做。

工具栏:吸引人,是吧?

GNR8 - the really spiffy toolbar

从左到右
连接 显示连接对话框以选择新服务器、目录或两者。
刷新 刷新当前视图。
生成 在应用程序路径中创建新的Template.txt文件。
自定义 显示自定义标记对话框。
默认值 显示默认标记。
关于 是的,无处不在的“关于”框。
退出 关闭 GNR8。

属性生成

只是关于 GNR8 目前生成的属性片段的说明;它们是简短形式的……

public virtual TYPE Foo { get; set; }

……其中TYPE是具体类型。

结论

GNR8,正如开头(很久以前)所说,是一个简单的应用程序,用于简单的任务:我想要一个快速方便的应用程序,它可以创建一组入门类,从而避免我输入所有那些烦人的属性片段:我乐于编写不同的存储过程(我们不都是这样吗?)和其他杂项,但希望基本的表处理完成并准备就绪。我提供的模板(可以通过我的其中一个漂亮的工具栏按钮生成)仅为例,您应该创建自己的模板。

历史

版本 1.0 - 2008 年 7 月 4 日

这基本上是第一个版本:我已经看到可以改进的地方,并且我将在时间允许的情况下实现它们。如果您确实发现了可以改进/更改/修复的地方,请告诉我,我将在此处更新并注明您的贡献。

一些改进将包括选择输出语言(我敢说 VB 吗?显然,我敢)或指定并使用,例如,Oracle 或 MySql 服务器,以及指定不同的模板。请将您的想法写在明信片上……

版权 © 2008, Mark Merrens。

© . All rights reserved.