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

生成 SQL 表的类表示

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (14投票s)

2009年12月14日

GPL3

5分钟阅读

viewsIcon

77343

downloadIcon

6418

自动将 SQL 表解析为 C# 类,并包含 insert、select 等函数。

引言

本项目构建了一个程序,该程序获取给定数据源(服务器)中所有数据库的列表,以及给定数据库名称内的表列表;然后为该表生成一个类抽象层。生成的类与表同名。如果需要,可以将该类表示形式保存为 .cs 源文件。

SqlClassFactory_solexp.jpg

代码解释

正如您在旁边看到的,该解决方案包含一个类库项目和一个作为启动项目的测试窗体项目。测试窗体包含两个窗体:TestMain.csInput.cs。Input 窗体获取数据源(通常是 '.' 用于受信任连接的服务器名称)。或者,它获取用于身份验证登录的服务器名称、用户 ID、密码条目。然后 TestForm 接管控制,如果输入有效,它会在屏幕上显示。否则应用程序退出。

sqlclassfactory 类库项目中,您可以看到不同的类。所有这些类都声明为 static。起点是 Constants 类。此类包含不易变的连接字符串等字符串。ConnStrArgs.cs 包含一个名为 Argsstatic 类。此类至关重要。因为它是在进行其他数据库操作之前必须设置的类。所有其他 static 类都从此类获取服务器信息。如下所示,必须先设置它

SqlClassFactory.Args.Reset();
SqlClassFactory.Args.Type = SqlClassFactory.enmConnStrType.Trusted;
SqlClassFactory.Args.DataSource = dataSource;
SqlClassFactory.Args.InitialCatalog = "master";

下一个类是 Connections.cs 类。此类有一个名为 _connectionprivate 字段,类型为 SqlConnection。它包含一个名为 GetConnection()static 方法。此方法从 Constants 获取格式字符串,并从 Args 类获取参数放入该格式字符串,然后构建新连接并返回。正如您所看到的,每次调用该方法时,都会使用可能被反复设置的 Args 创建新连接。

Commands 类只是原始 SqlCommands 的宿主类。命令的 CommandTextConnection 属性在 Adapters 中设置。在 Adapters 类中,这些属性的设置如下

Commands.ListDBCmd.CommandText = Constants.ListDBStr;
Commands.ListDBCmd.Connection = Connections.GetConnection();
Adapters._serverDA = new SqlDataAdapter(Commands.ListDBCmd);

例如,这里设置了 ListDBCmd 命令,并将 ServerDA 属性设置为具有此命令的 new SqlDataAdapter

最后一个类是 Generator 类。这个 static 类包含一个名为 BeginGeneration(string) 的方法。就像构造函数一样,此方法接受一个字符串参数 rawClassText 并将其内部化。我将在“使用代码”部分进行详细解释。

“Class.txt”

Class.txt 是包含 rawClassText 的文件。rawClassText 是用于从指定数据库生成表类的 string Class.txt 的一些字段是特殊字段 <...\>。这些字段被替换为其匹配项,例如 propertyNameclassName

public DataTable DoSelect(string SqlCommandText)
{
	SqlCommand selectCommand = new SqlCommand(SqlCommandText);
	selectCommand.Connection = sqlConnection;
	sqlDA.SelectCommand = selectCommand;
	DataTable retdt = new DataTable();
	sqlDA.Fill(retdt);
	return retdt;
}

这里您看到“Class.txt”的 DoSelect() 方法。这里 sqlDA 是类成员,在构造函数中初始化。此方法是类中最简单的方法。它填充 retdt 并返回它。

public bool DoInsert(string SqlCommandText, params object[] args)
{
	SqlCommand insertCommand = new SqlCommand(SqlCommandText);
	string argInCmd = null;
	Regex r = new Regex(@"@(\S+)", RegexOptions.IgnoreCase);
	int i = 0;
	if (r.Matches(SqlCommandText).Count == args.Length)
	{
		foreach (object arg in args)
		{
			argInCmd = r.Matches(SqlCommandText)[i].ToString();
			argInCmd = argInCmd.Trim().TrimEnd(new char[] {')', ','});
			insertCommand.Parameters.AddWithValue(argInCmd, arg);
			i++;
		}
	}
	else
		return false;
	insertCommand.Connection = sqlConnection;
	sqlConnection.Open();
	bool ret = insertCommand.ExecuteNonQuery() > 0;
	sqlConnection.Close();
	return ret;
}

这里您看到“Class.txt”的 DoInsert() 方法。此方法稍微复杂一些。它的用途是

DoInsert("Insert into Employees (firstname, lastname) values (@fname, @lname)", _
	"Ozgur", "Sonmez"); 

这是整个项目中“最聪明”的方法。它接受一个 params 参数 args。此参数包含要添加到 sqlcommand 的参数。在上面的示例中,argInCmd 字符串首先是 '@fname',然后是 '@lname'。argInCmd 恰好是 arg 的对应项。

new Regex(@"@(\S+)", RegexOptions.IgnoreCase); 

是 '@matched_parameter' 的匹配项。在通过 <r.Matches(SqlCommandText)[i].ToString();> 获取此项后,接着是修剪工作。出于某种原因,我无法让 C# 找到纯粹的匹配项。因此,一些匹配项带有 '@lname)' 或 '@fname,',所以我进行了修剪。现在,内部参数子字符串的纯匹配字符串存储在 argInCmd(命令中的参数)中。它通过 Parameter.AddWithValue() 方法添加到 sqlcommand 的参数中,然后就可以打开连接、执行非查询等操作了。

Using the Code

此源代码包含一个类库和一个测试窗体。为简洁起见,我使用了两个单独的 listbox 控件来查看来自 SqlClassFactory DLL 的数据库和相关表列表。类库是 SqlClassFactory.dll,主入口是 TestForm.exe。如果您愿意,可以真正使用类库来获取两个列表并在任何地方使用它们。这并不是 SqlClassLibrary 类所做的唯一工作。它还包括一个通用的 <Generator> 类,其中包含 <public static void BeginGeneration(string rawText)>。此方法从 Class.txt 文本文件中获取 rawText string 并替换所有 <...\> 为适当的名称。这是 Class.txt 的一个示例部分

namespace <database_name> 
{ public class <table_name> 
{ <column_name> 
SqlDataAdapter sqlDA = null; 
SqlConnection sqlConnection = null;

下面是 TestForm 应用程序的核心

SqlClassFactory.Generator.BeginGeneration(rtxtClass.Text);
SqlClassFactory.Generator.AddTableDBName(tableName, dbName);
foreach (DataRow row in dtColumns.Rows)
{
    SqlClassFactory.Generator.AddField
            (row["DATA_TYPE"].ToString(), row["COLUMN_NAME"].ToString());        
}
SqlClassFactory.Generator.EndGeneration();
 rtxtClass.Text = SqlClassFactory.Generator.RawClassText;

这里 BeginGenerator() static 方法从 richtextbox rtxtClass 获取 Text 数据,并将其内部化到 SqlClassFactory.Generator 类中。然后 Generator.AddTableDBName(..) 方法替换 rtxtClass.Text string 中的 "<database_name>" 和 "<table_name>" 为适当的名称。然后使用 Generator Static 类的 AddField() 方法的 foreach 循环,每次都将属性名称添加到原始类字符串中,该字符串来自 Class.txt。此方法依次替换 "<column_name>" 为属性名称——即给定数据库中给定表的列名——正如您从上面给出的参数中所见

row["DATA_TYPE"].ToString(), row["COLUMN_NAME"].ToString()

此函数值得关注。在该函数中,存在以下关键代码行

string fieldText =
                String.Format("public {0} {1}", propertyType, propertyName) 
                + " { get; set; }\n\t\t\t<column_name>";
RawClassText = RawClassText.Replace("<column_name>", fieldText);

这里,每次调用 AddField() 时,fieldtext 首先设置为 "public int productId { get; set; } <column_name>",第一个是属性类型,第二个是属性名,第三个是 column_name 标志,用于下一次 AddField() 调用,当调用时它会为新属性设置新行并添加第二个新行 "<column_name>"。

SqlClassFactory.Generator.EndGeneration();

此行代码将 "<column_name>" string 替换为 String.Empty,从而删除多余的内容。

rtxtClass.Text = SqlClassFactory.Generator.RawClassText;

通过这行代码,布局字符串被更改为结果字符串。

关注点

我了解到列名表也可以由行组成。:)

历史

这是第一个版本。

© . All rights reserved.