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

强类型数据集生成器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (9投票s)

2009 年 11 月 20 日

CPOL

4分钟阅读

viewsIcon

67018

downloadIcon

1333

生成强类型数据集

引言

当您启动 VS.NET 并创建一个新的 WinForm,然后向窗体添加数据网格视图时。您将通过几个向导步骤将此网格视图绑定到任何数据库中的特定表。该向导会指示您创建新连接,选择所需的项,然后您可以将特定列从任何表中拖放到网格视图中。
那么 VS.NET 是如何知道该做什么的呢?在生成的 XSD 架构文件中,它是如何获取数据库中的所有表和视图及其之间的关系的?

好了,VS.NET 向导会按照以下步骤生成强类型数据集架构文件和类文件:

  1. 创建 DataSet 类的新实例。
  2. 调用从服务器资源管理器将表或列拖放到强类型 DataSet 设计器上而创建的所有 SqlDataAdapter 对象的 FillSchema 方法。
  3. 调用 DataSet.WriteXmlSchema 方法来创建包含 DataSet 的新 .xsd 架构文件。
  4. 使用 XML Schema Definition Tool (XSD.exe) 根据 .xsd 文件生成强类型 DataSet 类。

此工具可用于为 C#、VB、JScript 和 Visual J# 语言生成 .xsd 架构文件和类文件。
要运行项目,您必须安装 VS.NET 2008 SP1 和 .NET Framework 3.5 SP1。
此工具是为 SQL Server 2005 构建的。

如何使用?

要观看此工具使用演示,请访问 Akram Mellice 的博客

要使用此工具,请按照以下步骤操作:

  1. 启动程序,服务器组合框将绑定到本地网络中的所有 SQL Server 实例。
  2. 输入用户名和密码,如果您使用 Windows 身份验证,则勾选“Windows 身份验证”复选框。
  3. 点击“测试连接”,如果提供的凭据成功,则该服务器上存在的所有数据库都将绑定到“数据库”组合框。
  4. 选择所需的数据库。
  5. 勾选您想要创建的项(例如:表、视图和关系)。
  6. 选择目标语言(例如 C#)。
  7. 您可以通过点击“保存生成的强类型数据集为”按钮将生成的文件保存到特定位置。
  8. 点击“查看选定的表”按钮,将打开“表查看器”窗体,您在第一个窗体中选择的所有项类型将在此窗体中显示。如果您只选择“表”,则在此窗体中只显示表;如果您选择“表”和“视图”,则此窗体中将显示所有表和视图。
  9. 选择所需的项(表或视图),然后点击“关闭”按钮。
  10. 点击“生成强类型数据集”按钮,应该会出现两个成功消息,告知 .xsd 架构文件和类文件已成功生成。

以下两张图片应该能阐明之前的步骤。

stronglytypeddatasetgeneratorform.png

tablesviewerform.png

Using the Code

源代码已完全文档化,因此我将在此处展示重要点。

  1. PrepareGeneratedDataSet() 方法
    string selectString = String.Empty;
    SqlCommand selectCommand = new SqlCommand(String.Empty, dbConnection);
    SqlDataAdapter selectAdapter = new SqlDataAdapter(selectCommand);
    int count = 0;
    //build the select statement and fix the selectAdapter's TableMapping
    foreach (DataRow row in selectedTables.Rows)
    {
      //Tables will be generated (Table_Type = Base Table)
      if (tablesChk.Checked)
      {
         if (row["TABLE_TYPE"].ToString().ToLower() == "base table")
         {
        selectString += "SELECT * FROM [" + row["Table_Name"].ToString() + "]; ";
        if (count == 0)
        {
               selectAdapter.TableMappings.Add("Table", row["Table_Name"].ToString());
           count++;
        }
        else
        {
               selectAdapter.TableMappings.Add("Table" 
                + count.ToString(), row["Table_Name"].ToString());
           count++;
        }
         }
       }
       //Tables will be generated (Table_Type = View)
       if (viewsChk.Checked)
       {
          if (row["TABLE_TYPE"].ToString().ToLower() == "view")
          {
         selectString += "SELECT * FROM [" + row["Table_Name"].ToString() + "]; ";
         if (count == 0)
         {
            selectAdapter.TableMappings.Add("Table", row["Table_Name"].ToString());
            count++;
         }
         else
         {
            selectAdapter.TableMappings.Add("Table" 
                + count.ToString(), row["Table_Name"].ToString());
            count++;
         }
          }
       }
    }       

    foreach 循环遍历所有选定的项;如果您选择了表和视图,它将把所有表名和视图名添加到 selectString 中,并根据整数计数来修正 selectAdapter 中的 TableMapping

  2. AddRelationsToGeneratedDataSet() 方法
    此方法中的重要部分是我用于获取选定数据库中所有表和视图之间所有关系的 SQL 查询。我在网上搜索了很多,阅读了数十份 MSDN 文档,以了解是否可以通过 ADO.NET 的方法获取关系,但一无所获,于是我转向了 SQL Server 本身。
    事实证明,它将此信息保存在系统表和视图中,以下查询用于获取此信息:
    SELECT OBJECT_NAME(SYS.FOREIGN_KEY_COLUMNS.CONSTRAINT_OBJECT_ID)
    AS RELATIONNAME, 
    OBJECT_NAME(SYS.FOREIGN_KEY_COLUMNS.PARENT_OBJECT_ID) AS CHILDTABLE,
    OBJECT_NAME(SYS.FOREIGN_KEY_COLUMNS.REFERENCED_OBJECT_ID) 
    AS PARENTTABLE, 
    SCHEMA_INFO_COLUMNS_1.COLUMN_NAME AS CHILDCOLUMN,
    SCHEMA_INFO_COLUMNS_2.COLUMN_NAME AS PARENTCOLUMN
    
    FROM SYS.FOREIGN_KEY_COLUMNS, 
         INFORMATION_SCHEMA.COLUMNS AS SCHEMA_INFO_COLUMNS_1,
         INFORMATION_SCHEMA.COLUMNS AS SCHEMA_INFO_COLUMNS_2
    
    WHERE OBJECT_NAME(SYS.FOREIGN_KEY_COLUMNS.PARENT_OBJECT_ID) =
          SCHEMA_INFO_COLUMNS_1.TABLE_NAME AND 
          SYS.FOREIGN_KEY_COLUMNS.PARENT_COLUMN_ID = 
          SCHEMA_INFO_COLUMNS_1.ORDINAL_POSITION AND 
          OBJECT_NAME(SYS.FOREIGN_KEY_COLUMNS.REFERENCED_OBJECT_ID) =
          SCHEMA_INFO_COLUMNS_2.TABLE_NAME AND 
          SYS.FOREIGN_KEY_COLUMNS.REFERENCED_COLUMN_ID = 
          SCHEMA_INFO_COLUMNS_2.ORDINAL_POSITION 

    此查询的返回数据如下(以 Northwind 为例):

    FK_Orders_Customers AS RELATIONNAME, Orders AS CHILDTABLE, _
    Customers AS PARENTTABLE, CustomerID AS CHILDCOLUMN, CustomerID AS PARENTCOLUMN.

    该方法的其余部分是根据选定项将检索到的关系插入 DataSet 的操作。

  3. GenerateBtn_Click(object sender, EventArgs e) 方法
    PrepareGeneratedDataSet();
    AddRelationsToGeneratedDataSet();
    if (xsdFilePath != String.Empty)
         ds.WriteXmlSchema(xsdFilePath);
    //call the XSD.exe
    string ApplicationName = 
    	@"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\XSD.exe";
    string parameters = "\"" + xsdFilePath 
                        + "\"" 
                        + " /d /o:" + "\"" 
                        + classFilePath + "\" /l:" 
                        + language;
    Process xsdProcess = new Process();
    xsdProcess.StartInfo.FileName = ApplicationName;
    xsdProcess.StartInfo.CreateNoWindow = true;
    xsdProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    xsdProcess.StartInfo.Arguments = parameters;
    xsdProcess.Start();
    xsdProcess.WaitForExit();

    此方法准备好要生成的数据集,并向其中添加关系,然后将数据集的内容写入 XSD 文件,然后调用 .NET SDK 的一部分 XSD.exe 来生成类。

历史

  • 2009 年 11 月 20 日:初始发布
  • 2009 年 12 月 1 日:更新以修复以下两个问题
    1. 正确处理 Windows 身份验证
    2. 处理基于多个列的关系

    第一个问题很简单,只需将 connectionBuilder.IntegratedSecurity = true 设置为 true 即可。

    对于第二个问题,我更改了 AddRelationsToGeneratedDataSet 方法的代码,如下所示:

    //check if the relation is based on more than one column
    if (ds.Relations.Contains(row["RELATIONNAME"].ToString()))
    {
    int columnCount = ds.Relations[row["RELATIONNAME"].ToString()].ChildColumns.Length;
    for (int i = 0; i < columnCount; i++)
    {
    if (ds.Relations[row["RELATIONNAME"].ToString()].ChildColumns[i].ColumnName.Equals
    (ds.Tables[row["CHILDTABLE"].ToString()].Columns[row["CHILDCOLUMN"].ToString()]) &&
    ds.Relations[row["RELATIONNAME"].ToString()].ParentColumns[i].ColumnName.Equals
    (ds.Tables[row["PARENTTABLE"].ToString()].Columns[row["PARENTCOLUMN"].ToString()]))
    {
    string errorMessage = @"The relation " 
    + ds.Relations[row["RELATIONNAME"].ToString()] 
    + " between the tables " + ds.Tables[row["PARENTTABLE"].ToString()]
    + " and " + ds.Tables[row["CHILDTABLE"].ToString()] + " on the columns " + 
    ds.Tables[row["PARENTTABLE"].ToString()].Columns[row["PARENTCOLUMN"].ToString()]
    + " and " + ds.Tables[row["CHILDTABLE"].ToString()].Columns
    [row["CHILDCOLUMN"].ToString()] + " already exist.";
    MessageBox.Show(errorMessage, "Error!");
    return;
    }
    else
    {
    DataColumn[] newParentColumns = new DataColumn[ds.Relations
    [row["RELATIONNAME"].ToString()].ParentColumns.Length + 1];
    ds.Relations[row["RELATIONNAME"].ToString()].
    ParentColumns.CopyTo(newParentColumns, 0);
    newParentColumns[ds.Relations[row["RELATIONNAME"].ToString()].
    ParentColumns.Length] = ds.Tables[row["PARENTTABLE"].ToString()].
    Columns[row["PARENTCOLUMN"].ToString()];
    DataColumn[] newChildColumns = new DataColumn[ds.Relations
    [row["RELATIONNAME"].ToString()].ChildColumns.Length + 1];
    ds.Relations[row["RELATIONNAME"].ToString()].
    ChildColumns.CopyTo(newChildColumns, 0);
    newChildColumns[ds.Relations[row["RELATIONNAME"].ToString()].
    ChildColumns.Length] = ds.Tables[row["CHILDTABLE"].ToString()].
    Columns[row["CHILDCOLUMN"].ToString()];
    ds.Relations.Remove(row["RELATIONNAME"].ToString());
    ds.Relations.Add(row["RELATIONNAME"].ToString(), 
    newParentColumns, newChildColumns);
    }
    }
    }
    else
    ds.Relations.Add(row["RELATIONNAME"].ToString(), ds.Tables
    [row["PARENTTABLE"].ToString()].Columns[row["PARENTCOLUMN"].ToString()], 
    ds.Tables[row["CHILDTABLE"].ToString()].Columns[row["CHILDCOLUMN"].ToString()]);

    我还添加了一个名为“设置 xsd.exe 路径”的按钮,如果 xsd.exe 工具不存在于默认位置“C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\”中,则可以使用它来设置其路径。

© . All rights reserved.