C# DBNull and nullable Types - cleanest form of conversion

こ雲淡風輕ζ 提交于 2019-12-18 10:39:31

问题


I have a DataTable, which has a number of columns. Some of those columns are nullable.

DataTable dt;  // Value set. 
DataRow dr;  // Value set. 

// dr["A"] is populated from T-SQL column defined as: int NULL 

What, then, is the cleanest form of converting from a value in a DataRow, to a nullable variable.

Ideally, I would be able to do something like:

int? a = dr["A"] as int?; 

Edit: Turns out you CAN do this, the side effect being that if your Schema types arn't ints, then this is ALWAYS going to return null. The answer by Ruben of using dr.Field<int?>("A") ensures type mismatches don't silently fail. This, of course, will be picked up by thorough unit tests.

Instead I'm usually typing something along the lines of:

int? a = dr["A"] != DBNull.Value ? (int)dr["A"] : 0; 

This is a bunch more keystrokes, but more importantly, there's more room for someone to stuff something up with a wrong keystroke. Yes, a Unit Test will pick this up, but I'd rather stop it altogether.

What is the cleanest, least error-prone pattern for this situation.


回答1:


The LINQ to DataSets chapter of LINQ in Action is a good read.

One thing you'll see is the Field<T> extension method, which is used as follows:-

int? x = dr.Field<int?>( "Field" );

Or

int y = dr.Field<int?>( "Field" ) ?? 0;

Or

var z = dr.Field<int?>( "Field" );



回答2:


This is the purpose of the DataRowExtensions class in .NET 3.5, which provides static Field<T> and SetField<T> methods for round-tripping nullable (and non-nullable) data between the DataRow and .NET types.

int? fld = row.Field<int?>("ColumnA")

will set fld to null if row["ColumnA"] contains DBNull.Value, to its value if it contains an integer, and throw an exception if it contains anything else. And on the way back,

row.SetField("ColumnA", fld);

does the same thing in reverse: if fld contains null, it sets row["ColumnA"] to DBNull.Value, and otherwise sets it to the value of fld.

There are overloads of Field and SetField for all of the value types that DataRow supports (including non-nullable types), so you can use the same mechanism for getting and setting fields irrespective their data type.




回答3:


int? a = (int?)dr["A"]



回答4:


Why not use LINQ? It does the conversion for you.




回答5:


Following would work, safely:

Snip:

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

Usage:

SqlDataReaderEx.TryParse(drReader, "MyColumnName", -1);



回答6:


Extension methods!

Something like the following:

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

Use it like so:

int? a = dr.GetNullableValue<int>("A");

or

string b = dr.GetValue<string>("B");



回答7:


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

To call the function you could write

var dt = new DataTable();
dt.Columns.Add("ColumnName");
....
Add rows in Datatable.
....
dt.Rows[0].GetColumnValue("ColumnName);



回答8:


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


来源:https://stackoverflow.com/questions/1706405/c-sharp-dbnull-and-nullable-types-cleanest-form-of-conversion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!