【问题标题】:Set a specific column in a DataRow在 DataRow 中设置特定列
【发布时间】:2012-10-10 21:56:57
【问题描述】:

我正在尝试将一组规则“批量”插入到规则表中。该表的结构如下:

RuleId int,
Rule nvarchar(256),
Domain nvarchar(256),
RuleTypeId int,
ExpirationDate DateTime

在我的插入函数中,我尝试在获得表的架构后设置一行的列,但似乎该行不包含指定的列(请注意,我没有指定RuleId,因为它是自动生成的):

private void InsertRulesXml(List<Rule> rules)
{
    using (DataSet ds = new DataSet())
    {
        using (DataTable rulesTable = GetSchemeForTable("RulesTable"))
        {
            // Add the rules to the table
            foreach (Rule rule in rules)
            {
                DataRow row = rulesTable.NewRow();

                // When I try to set the specific column it tells me that the column doesn't exist
                row["Rule"] = rule.Rule;
                row["Domain"] = rule.Domain;
                row["RuleTypeId"] = rule.RuleTypeId;
                row["ExpirationDate"] = rule.Expiration;

                rulesTable.Rows.Add(row);
            }
            ds.Tables.Add(rulesTable);

            // Convert the data to XML
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                rulesTable.WriteXml(sw, System.Data.XmlWriteMode.WriteSchema);
            }

            // Insert the XML rules
            InsertUpdateRulesXml(sb.ToString());
        }
    }
}

这里是获取指定表架构的函数:

private DataTable GetSchemeForTable(string tableName)
{
    DataTable ret = null;

    using (SqlConnection connection = GetContentScraperSqlConnection())
    {
        try
        {
            connection.Open();
            SqlCommand command = connection.CreateCommand();
            command.CommandText = string.Format("SELECT TOP 0 [{0}].* FROM [{0}] WHERE 1 = 2;", tableName);
            using (IDataReader reader = command.ExecuteReader(CommandBehavior.SchemaOnly))
            {
                ret = reader.GetSchemaTable();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception in GetSchemeForTable: " + ex.ToString());
        }
        finally
        {
            if (connection.State == ConnectionState.Open)
            {
                connection.Close();
            }
            connection.Dispose();
        }
    }

    return ret;
}

问题:当我尝试设置特定列时,它告诉我该列不存在。
异常消息:

An unhandled exception of type 'System.ArgumentException' occurred in System.Data.dll

Additional information: Column 'Rule' does not belong to table SchemaTable.

我怀疑获取表模式实际上并没有给我Rule 表,而是SchemaTable。我真正想要的是与Rule 表对应的DataTable(即它具有相同的架构)。

问题:给定记录列表的行中设置列值的正确方法是什么?

【问题讨论】:

  • 为什么不检查一下列名是什么?您应该能够执行类似“foreach (DataColumn col in rulesTable.Columns) { Console.WriteLine(col.Name); }”之类的操作,也许正在自动生成一个奇怪的名称。另一种选择是使用列索引。
  • rulesTable 将包含 ColumnName、ColumnOrdinal、ColumnSize、NumericPrecision 等列。它代表的是模式表,而不是表 (RuleTable) 本身。
  • @amit_g 是的,这就是我面临的问题......我如何获得实际的 RulesTable 表本身?
  • 我注意到的另一件事。您的 SQL 查询不应返回任何内容。您选择了 TOP 0(因为没有行)。我认为您可能需要一些结果才能让 reader.GetSchemaTable() 工作。
  • 您必须使用 rulesTable 中的行值动态创建表。

标签: c# sql datatable dataset datacolumn


【解决方案1】:

GetSchemaTable 并没有像您期望的那样做。它返回一个DataTable,其中行是源表的列,列是关于这些列的元数据。

如果您想使用给定表的架构获得“空”DataTable,请将您的函数更改为:

private DataTable GetSchemeForTable(string tableName)
{
    DataTable ret = new DataTable();

    try
    {
        connection.Open();
        SqlCommand command = connection.CreateCommand();
        command.CommandText = string.Format("SELECT * FROM [{0}] WHERE 1 = 2;", tableName);
        using (IDataReader reader = command.ExecuteReader(CommandBehavior.SchemaOnly))
        {
            ret.Load(reader);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception in GetSchemeForTable: " + ex.ToString());
    }
    finally
    {
        if (connection.State == ConnectionState.Open)
        {
            connection.Close();
        }
        connection.Dispose();
    }

    return ret;
}

请注意,我取出了 using 块,因为无论如何您都要在 finally 块中处理连接(这基本上就是 using 所做的)。

【讨论】:

    【解决方案2】:

    也许你可以使用这样的东西来生成你的表格:

    GenerateDataTable(typeof(Rule));
    
    private DataTable GenerateRulesDataTable(Type type)
    {
        DataTable table = new DataTable();
    
        // build table columns
        foreach (PropertyInfo propInfo in type.GetProperties())
        {
            Type colType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
            DataColumn col = new DataColumn(propInfo.Name, colType);
            table.Columns.Add(col);
        }
    
        return table;
    }
    

    【讨论】:

    • 不确定,但我认为如果以这种方式创建 DataTable,更新将不起作用
    • 我认为你应该没问题。每列的名称取自您的 Rule 对象。只要确保对象与数据库保持一致,就可以了。虽然如果让 .NET 完成所有 sql 查询管理,可能会遇到问题。
    • 这是一个很好的解决方案,只要 Rule 类包含具有匹配名称的属性(即列的名称与属性的名称匹配),它就会起作用。在我的情况下并非如此,但这绝对是一种有效的方法。谢谢:)
    【解决方案3】:

    GetSchemaTable 不会返回与 DataReader select 返回的结构相同的 DataTable,它会返回具有相同架构(ColumnName、ColumnSize 等)的表,并且您的架构位于 DataTable 行中。

    在您的情况下,您应该使用此选择获得 DataTable,然后您将获得空的 RulesTable。这样,您将能够将新行插入返回的 DataTable(在您的情况下为 rulesTable)并更新回数据库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 2017-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多