我有一个DataTable,它有很多列。其中一些列可以为空。
DataTable dt; // Value set.
DataRow dr; // Value set.
// dr["A"] is populated from T-SQL column defined as: int NULL
那么,从DataRow中的值转换为可空变量的最干净的形式是什么。
理想情况下,我可以做类似的事情:
int? a = dr["A"] as int?;
编辑 :原来你可以这样做,副作用是如果你的Schema类型没有整数,那么这总是会返回空值。 Ruben使用dr.Field<int?>("A")
的答案确保类型不匹配不会无声地失败。当然,这将通过彻底的单元测试来获取。
相反,我通常会按照以下方式键入内容:
int? a = dr["A"] != DBNull.Value ? (int)dr["A"] : 0;
这是一堆更多的击键,但更重要的是,有更多的空间让某人用错误的击键来填充内容。 是的,单元测试会选择它,但我宁愿完全停止它。
对于这种情况,最干净,最容易出错的模式是什么?
答案 0 :(得分:54)
The LINQ to DataSets chapter of LINQ in Action读得很好。
您将看到的一件事是Field<T>
扩展方法,其使用方法如下: -
int? x = dr.Field<int?>( "Field" );
或者
int y = dr.Field<int?>( "Field" ) ?? 0;
或者
var z = dr.Field<int?>( "Field" );
答案 1 :(得分:12)
这是.NET 3.5中DataRowExtensions
类的目的,它提供静态Field<T>
和SetField<T>
方法,用于在{之间绕过可空(和非可空)数据。 {1}}和.NET类型。
DataRow
如果int? fld = row.Field<int?>("ColumnA")
包含fld
,会将null
设置为row["ColumnA"]
,如果它包含整数,则将其设置为其值,如果包含任何其他内容,则抛出异常。在回来的路上,
DBNull.Value
反过来做同样的事情:如果row.SetField("ColumnA", fld);
包含fld
,则会将null
设置为row["ColumnA"]
,否则将其设置为DBNull.Value
的值。
fld
支持的所有值类型(包括非可空类型)都存在Field
和SetField
的重载,因此您可以使用相同的机制进行获取和设置字段与其数据类型无关。
答案 2 :(得分:4)
int? a = (int?)dr["A"]
答案 3 :(得分:1)
为什么不使用LINQ?它为您进行转换。
答案 4 :(得分:1)
以下会安全地工作:
<强>剪断:强>
public static class SqlDataReaderEx
{
public static int TryParse(SqlDataReader drReader, string strColumn, int nDefault)
{
int nOrdinal = drReader.GetOrdinal(strColumn);
if (!drReader.IsDbNull(nOrdinal))
return drReader.GetInt32(nOrdinal);
else
return nDefault;
}
}
<强>用法:强>
SqlDataReaderEx.TryParse(drReader, "MyColumnName", -1);
答案 5 :(得分:0)
扩展方法!
如下所示:
public static class DataRowExtensions
{
public static Nullable<T> GetNullableValue<T>(this DataRow row, string columnName)
where T : struct
{
object value = row[columnName];
if (Convert.IsDBNull(value))
return null;
return (Nullable<T>)value;
}
public static T GetValue<T>(this DataRow row, string columnName)
where T : class
{
object value = row[columnName];
if (Convert.IsDBNull(value))
return null;
return (T)value;
}
}
像这样使用它:
int? a = dr.GetNullableValue<int>("A");
或
string b = dr.GetValue<string>("B");
答案 6 :(得分:-1)
public static object GetColumnValue(this DataRow row, string columnName)
{
if (row.Table.Columns.Contains(columnName))
{
if (row[columnName] == DBNull.Value)
{
if (row.Table.Columns[columnName].DataType.IsValueType)
{
return Activator.CreateInstance(row.Table.Columns[columnName].DataType);
}
else
{
return null;
}
}
else
{
return row[columnName];
}
}
return null;
}
要调用您可以编写的功能
var dt = new DataTable();
dt.Columns.Add("ColumnName");
....
Add rows in Datatable.
....
dt.Rows[0].GetColumnValue("ColumnName);
答案 7 :(得分:-4)
Chart.data = new List < int ?> ();
Chart.data = (from DataRow DR in _dtChartData.Rows
select(int ? )((DR[_ColumnName] == DBNull.Value) ? (int ? ) null : (int ? ) DR[_ColumnName])).ToList();