2

添付されたコードで db null 値を確認するにはどうすればよいですか? 私は新しい C# 変換であることを理解してください...

このコードが行うことは、IDataReader オブジェクトを取得し、それを厳密に型指定されたオブジェクトのリストに変換してマップすることです。しかし、私が見つけたのは、リーダーに null 列が返されると完全にエラーになることです。

コンバータ

internal class Converter<T> where T : new()
{
    // Declare our _converter delegate
    readonly Func<IDataReader, T> _converter;
    // Declare our internal dataReader
    readonly IDataReader dataReader;

    // Build our mapping based on the properties in the class/type we've passed in to the class
    private Func<IDataReader, T> GetMapFunc()
    {
        // declare our field count
        int _fc = dataReader.FieldCount;
        // declare our expression list
        List<Expression> exps = new List<Expression>();
        // build our parameters for the expression tree
        ParameterExpression paramExp = Expression.Parameter(typeof(IDataRecord), "o7thDR");
        ParameterExpression targetExp = Expression.Variable(typeof(T));
        // Add our expression tree assignment to the exp list
        exps.Add(Expression.Assign(targetExp, Expression.New(targetExp.Type)));
        //does int based lookup
        PropertyInfo indexerInfo = typeof(IDataRecord).GetProperty("Item", new[] { typeof(int) });
        // grab a collection of column names from our data reader
        var columnNames = Enumerable.Range(0, _fc).Select(i => new { i, name = dataReader.GetName(i) }).AsParallel();
        // loop through all our columns and map them properly
        foreach (var column in columnNames)
        {
            // grab our column property
            PropertyInfo property = targetExp.Type.GetProperty(column.name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            // check if it's null or not
            if (property != null)
            {
                // build our expression tree to map the column to the T
                ConstantExpression columnNameExp = Expression.Constant(column.i);
                IndexExpression propertyExp = Expression.MakeIndex(paramExp, indexerInfo, new[] { columnNameExp });
                UnaryExpression convertExp = Expression.Convert(propertyExp, property.PropertyType);
                BinaryExpression bindExp = Expression.Assign(Expression.Property(targetExp, property), convertExp);
                // add it to our expression list
                exps.Add(bindExp);
            }
        }
        // add the originating map to our expression list
        exps.Add(targetExp);
        // return a compiled cached map
        return Expression.Lambda<Func<IDataReader, T>>(Expression.Block(new[] { targetExp }, exps), paramExp).Compile();
    }

    // initialize
    internal Converter(IDataReader dataReader)
    {
        // initialize the internal datareader
        this.dataReader = dataReader;
        // build our map
        _converter = GetMapFunc();
    }

    // create and map each column to it's respective object
    internal T CreateItemFromRow()
    {
        return _converter(dataReader);
    }
}

マッパー

    private static IList<T> Map<T>(DbDataReader dr) where T : new()
    {
        try
        {
            // initialize our returnable list
            List<T> list = new List<T>();
            // fire up the lamda mapping
            var converter = new Converter<T>(dr);
            while (dr.Read())
            {
                // read in each row, and properly map it to our T object
                var obj = converter.CreateItemFromRow();
                // add it to our list
                list.Add(obj);
            }
            // reutrn it
            return list;
        }
        catch (Exception ex)
        {
            // make sure this method returns a default List
            return default(List<T>);
        }
    }

型付きオブジェクトへの列がここで発生する場所がよくわからないので、自分でやろうと思います...しかし、それがどこにあるのかわかりません。

これはおそらくあまり役​​に立たないことはわかっていますが、私が得ているエラーは次のとおりです。

Unable to cast object of type 'System.DBNull' to type 'System.String'.

そしてそれはで起こります

internal T CreateItemFromRow()
    {
        return _converter(dataReader); //<-- Here
    }

ノート

クエリ自体の列を ISNULL(column, '') でラップすると、これは発生しませんが、これは確かに解決策ではないことを理解できると思います

4

3 に答える 3

2

これは、一般的にデータセットを扱う上で最も厄介な問題の 1 つです。

私が通常それを回避する方法は、DBNull 値を実際の null や、場合によっては空白の文字列など、より便利なものに変換することです。これにはさまざまな方法がありますが、つい最近、拡張メソッドを使用するようになりました。

public static T? GetValueOrNull<T>(this object value) where T : struct
        {
            return value == null || value == DBNull.Value ? (T?) null : (T) Convert.ChangeType(value, typeof (T));
        }

null 許容型の便利な拡張メソッドです。たとえば、次のようになります。

int? myInt = DataSet.Tables[0].Rows[0]["DBNullInt"].GetValueOrNull<int>();

または、DBNull を null に変換するだけの、より一般的なもの:

public static object GetValueOrNull(this object value)
        {
            return value == DBNull.Value ? null : value;
        }

string myString DataSet.Tables[0].Rows[0]["DBNullString"].GetValueOrNull();

文字列に a を入れようとするのではなく、null 文字列を取得しますDBNull

うまくいけば、それはあなたを少し助けるかもしれません.

于 2013-12-06T15:37:02.763 に答える