我正在尝试执行"批量"将一组规则插入规则表中。该表具有以下结构:
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
表的数据表(即它具有相同的模式)。
问:在给定记录列表的行中设置列值的正确方法是什么?
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
所做的)。
也许您可以使用这样的东西来生成表:
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;
}
GetSchemaTable 不会返回结构与 DataReader select 返回的结构相同的 DataTable,它会还原具有相同架构(ColumnName、ColumnSize 等)的表,并且您的架构位于 DataTable 行中。
在您的情况下,您应该使用此选择获取数据表,然后您将获得空的规则表。这样,您将能够将新行插入到返回的 DataTable(在您的例子中为 ruleTable)中,并执行"更新回数据库"。