提问人:Tom 提问时间:11/10/2023 最后编辑:derloopkatTom 更新时间:11/10/2023 访问量:78
由于 DBNulls 而转换数据类型时出错
Error while converting Datatype due to DBNulls
问:
我正在尝试通过从一个数据库调用存储过程来使用我的 c# 应用程序加载数据,然后需要将该数据插入到另一个数据库中。我打算使用它的 SQL 批量插入。我确实提出了 SSIS,但不幸的是,他们没有软件和基础设施。我需要转换某些列的数据类型,因为当我批量插入目标表时它会爆炸。我正在使用函数进行转换,但不幸的是在尝试转换值时出现错误。当我尝试在转换前检查值时,它似乎没有进入 If 条件块。有人能告诉我我哪里出了问题吗?DBNull
DBNull
using (SqlConnection con = new SqlConnection(_SourceConnectionString))
{
// con.Open();
// Create a table with some rows.
DataTable table = new DataTable();
var cmd = new SqlCommand("[EMR].[spOrderDailySummary]", con);
var da = new SqlDataAdapter(cmd);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@OrderDate", SqlDbType.DateTime).Value = _businessDate;
try
{
// LogManager.Log(LogSeverity.Info, $"Initiating report {rgc.ReportType}.");
da.Fill(table);
table.ConvertColumnType("Original_Qty", typeof(int));
table.ConvertColumnType("Remaining_Qty", typeof(int));
table.ConvertColumnType("Price", typeof(decimal));
table.ConvertColumnType("OrderDate", typeof(DateTime));
table.ConvertColumnType("Valid_to_Value", typeof(DateTime));
table.ConvertColumnType("ClientID", typeof(int));
table.ConvertColumnType("Trigger_Price", typeof(decimal));
table.ConvertColumnType("Investment_Decision_Within_Firm", typeof(int));
table.ConvertColumnType("Order_Priority_Timestamp", typeof(DateTime));
table.ConvertColumnType("Transaction_Time", typeof(DateTime));
table.ConvertColumnType("NewOrdDateTime", typeof(DateTime));
StartDataMigration(table);
}
}
执行转换的函数
public static void ConvertColumnType<T>(this DataTable dt, string columnName, Type newType) where T : Type, IConvertible
{
using (DataColumn dc = new DataColumn(columnName + "_new", newType))
{
// Add the new column which has the new type, and move it to the ordinal of the old column
int ordinal = dt.Columns[columnName].Ordinal;
dt.Columns.Add(dc);
dc.SetOrdinal(ordinal);
// Get and convert the values of the old column, and insert them into the new
foreach (DataRow dr in dt.Rows)
if (dr[dc.ColumnName] != DBNull.Value)
{
dr[dc.ColumnName] = Convert.ChangeType(dr[columnName], newType);
}
// Remove the old column
dt.Columns.Remove(columnName);
// Give the new column the old column's name
dc.ColumnName = columnName;
}
}
答:
0赞
Joel Coehoorn
11/10/2023
#1
这一行是有问题的:
if (dr[dc.ColumnName] != DBNull.Value)
原因有两方面。首先,与使用 and 运算符相比,可能会发生奇怪的事情。这样会更好:DBNull.Value
!=
==
if (!DBNull.Value.Equals(dr[dc.ColumnName]))
此外,上面的代码正在查看尚未设置值的新列名称。此时我们仍然需要引用旧列,因此我们想要:
if (!DBNull.Value.Equals(dr[columnName]))
评论
0赞
Tom
11/10/2023
您建议的这种检查肯定更好。我收到错误,说对象应该实现 IConvertible 。所以我更新了我的帖子,以展示我是如何做到的。不确定如何调用该方法
0赞
Tom
11/10/2023
如何称呼此表。ConvertColumnType<我在这里传递什么?>(“Original_Qty”, typeof(int));
0赞
Joel Coehoorn
11/10/2023
@Tom泛型必须在编译时解析。在那里没有办法使用运行时类型实例。您可能需要 switch 语句或类似语句来为 DataTable 支持的每种类型调用单独的方法,或者在一个方法中调用一个开关。但是你可以指定类型名称,即问题是它是需要可转换的旧类型。table.ConvertColumnType<int>("Original_Qty", typeof(int));
0赞
Tom
11/10/2023
如果我按表打电话。ConvertColumnType<int>(“Original_Qty”, typeof(int)) ,我收到错误 int 不能用作参数 没有从“int”到“T”的装箱转换
0赞
Tom
11/10/2023
我不太确定您的意思是否需要在一个方法中使用 switch 语句。我需要在 switch 语句中检查什么
评论
dt.Columns.Add(dc);
添加对 but 对象的引用被创建到语句中并被释放。我还没有测试过这段代码,但我建议在离开代码块后调试并检查是否包含新添加的列。dc
using
dt.Columns
using
{ ... }
if (dr[dc.ColumnName]
应该是 ?if (dr[columnName]
using
==
!=
DBNull.Value.Equals()
IsDBNull()