2

I'm trying to perform a "bulk" insert a set of rules into a table of rules. The table has the following structure:

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

In my insertion function I try to set the columns of a row after I've obtained the schema of the table, but it appears that the row does not contain the specified column (note that I don't specify the RuleId since it's auto-generated):

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());
        }
    }
}

Here is the function that gets the schema for the specified table:

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;
}

Problem: When I try to set the specific column it tells me that the column doesn't exist.
Exception Message:

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

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

I suspect that the getting the table schema does not actually give me Rule table, but the SchemaTable. What I really want to get is the DataTable which corresponds to the Rule table (i.e. it has the same schema).

Question: What's the proper way to set the column values in a row given a list of records?

4

3 回答 3

3

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这样做的)。

于 2012-10-10T22:08:09.727 回答
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;
}
于 2012-10-10T22:09:15.430 回答
0

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

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

于 2012-10-10T22:06:39.653 回答