【发布时间】:2015-11-10 14:41:41
【问题描述】:
我想将 DataRow 中的值转换为强类型变量。我想到了类似的东西:
int id = row.Field<int>("ID");
但问题是,我们的标准 Db-Select 返回一个 DataTable 其中每个值都是字符串类型。意味着每个值都是对象,列没有特定类型。通过这个Field<T> 抛出 InvalidCastException 因为我尝试将对象转换为 int。
所以我自己做了一些事情:
public static T ConvertTo<T>(this DataRow row, string columnName)
{
T returnValue = default(T);
Type typ = Nullable.GetUnderlyingType(typeof(T));
if ((row != null) &&
(row[columnName] != null) &&
(!Convert.IsDBNull(row[columnName])))
{
if (typ == null)
{
returnValue = (T)Convert.ChangeType(row[columnName], typeof(T));
}
else
{
returnValue = (T)Convert.ChangeType(row[columnName], typ);
}
}
return returnValue;
}
此方法按预期工作。我可以转换可为空的值、字符串和值类型。好的,如果有人输入像自己的类型这样的废话,我需要捕获异常。但其他都很好。
但是,如果我加载一个包含 30000 行和 20 列的 DataTable,并希望使用此方法来转换每个值以创建对象,我会遇到巨大的性能缺陷。如果我对每个值使用int id = Convert.ToInt32(row["ID"]); 等等,它比我的一般方法快 5-6 倍。但我不喜欢手动转换它们,特别是如果有很多DBNull.Value。
我认为问题在于通过以下方式获取基础类型:
Type typ = Nullable.GetUnderlyingType(typeof(T));
这是反射调用并减慢我的方法。这是正确的吗?有没有人遇到同样的问题并且有一个快速的解决方案?
更新:
我们的标准选择是这样工作的:
DbDataAdapter dataAdapter = new DbDataAdapter();
dataAdapter.SelectCommand = cmd;
dataSet = new DataSet();
dataAdapter.Fill(dataSet);
dtReturn = dataSet.Tables[0].Copy();
DbDataAdapter 内部使用 OracleDataAdapter。
更新:
为了澄清,我正在做以下事情(只是一个小例子):
我有一个代表选择查询的类。例如:
public class Customer
{
public int Id{get;set}
public string Name{get;set}
}
在数据库 (Oracle) 中,我有一个“客户”表,其中有 2 列 Id number(5) 和 Name varchar2(100)。
现在我想阅读所有客户并将它们转换为客户对象。 所以我通过我们的标准例程 SqlSelect 读取数据。这返回给我一个数据表。这个方法的实习生是在第一次UPDATE之前贴出来的。
现在我遍历此 DataTable 中的每个 DataRow 并转换此单元格值以创建对象。
List<Customer> myList = new List<Customer>();
foreach (DataRow row in SqlSelect())
{
Customer customer = new Customer();
customer.Id = Convert.ToInt32(row["ID"]);
customer.Name = Convert.ToString(row["NAME"]);
myList.Add(customer);
}
这样就好了。但我想像这样转换:
customer.Id = row.ConvertTo<int>("ID");
如果我在 row["ID"] 处的 DataTable 是 int 字段方法可以很好地处理这个问题。特别是如果还有其他列可以为空等。但在我的情况下,行[“ID”](以及每个选择的所有其他值)是字符串。所以菲尔德不能施放这个。我的 ConvertTo 可以做到,但在大型表上性能欠佳。
【问题讨论】:
-
使用分析器。为什么我们会知道您的 CPU 将时间花在哪里?此外,使用
Convert也有没有的意义。该值要么是DBNull.Value,要么是T类型——只需进行简单的转换即可。 -
您的“标准数据库选择返回无类型数据表”?这怎么可能?你怎么填那张桌子?通常
DataAdapter从数据读取器中检索模式信息。 “我不喜欢手动转换它们,特别是如果有很多DBNull.Value”。DBNull.Value有什么问题?DataRow.Field支持可为空的类型。 -
@TimSchmelter 如果我可以使用 Field
方法,我不会对 DBNull.Value 有任何问题。如果我用 Convert.ToInt32() 等转换每个值,那就太划算了。但是 Field 方法不能像上面解释的那样工作。 -
@Sebi:为什么在返回之前复制整个表?如果您不需要填写的
DataSet用于其他目的,您可以return dataSet.Tables[0] -
@TimSchmelter 感谢您的提示。我没有开发这个程序。这是我们的标准,由一位同事制定。我会问他...
标签: c# type-conversion nullable datarow