如何(有效地)将SqlDataReader字段转换(转换)为其对应的c#类型? [英] How to (efficiently) convert (cast?) a SqlDataReader field to its corresponding c# type?

查看:323
本文介绍了如何(有效地)将SqlDataReader字段转换(转换)为其对应的c#类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,让我解释一下当前的情况:我正在从一个数据库中读取记录,并将它们放在一个对象中供以后使用;今天一个问题关于数据库类型到C#类型转换(转换)。



让我们看一个例子:

 命名空间测试
{
使用System;
using System.Data;
using System.Data.SqlClient;

public enum MyEnum
{
FirstValue = 1,
SecondValue = 2
}

public class MyObject
{
private String field_a;
private Byte field_b;
private MyEnum field_c;

public MyObject(Int32 object_id)
{
using(SqlConnection connection = new SqlConnection(connection_string))
{
connection.Open ;

using(SqlCommand command = connection.CreateCommand())
{
command.CommandText =sql_query;

使用(SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow))
{
reader.Read();

this.field_a = reader [field_a];
this.field_b = reader [field_b];
this.field_c = reader [field_c];
}
}
}
}
}
}

这显然是失败的,因为三个 this.field_x = reader [field_x]; 调用抛出不能将类型object隐式转换为xxx。显示转换存在(是否缺少转换?)编译器错误。



知道两种方法(让我们使用 field_b 示例):第一个是 this.field_b =(Byte)reader [field_b]; code>,第二个是 this.field_b = Convert.ToByte(reader [field_b]);



选项号1的问题是 DBNull 字段抛出异常,因为转换失败(即使是可空类型 String ),ant第二个问题是它不保留空值( Convert.ToString(DBNull)产生一个 String 。



因此,在互联网上的几次查找后,在这里StackOverflow,我想出了:

  public static class实用程序
{
public static T FromDatabase ; T>(Object value)其中T:IConvertible
{
if(typeof(T).IsEnum == false)
{
if(value == null || Convert.IsDBNull(value)== true)
{
return default(T);
}
else
{
return(T)Convert.ChangeType(value,typeof(T));
}
}
else
{
if(Enum.IsDefined(typeof(T),value)== false)
{
throw new ArgumentOutOfRangeException();
}

return(T)Enum.ToObject(typeof(T),value);
}
}
}



问题是:我错过了什么?我在做一个WOMBAT(浪费金钱,大脑和时间),因为有一个更快,更干净的方式做到吗?这是正确的吗?利润?

解决方案

如果字段允许空值,请不要使用常规基本类型。使用 C#可空的类型 keyword

  int? field_a = reader [field_a] as int? 
string field_b = reader [field_a] as string;

添加到任何不可为空C#类型使它可空。使用作为关键字将尝试将对象转换为指定的类型。如果转换失败(类似于 DBNull ),则操作符返回 null



注意:使用作为的另一个小好处是它比正常投放稍快。因为它也可以有一些缺点,如使你更难跟踪错误,如果你尝试转换为错误的类型,这不应该被认为是总是使用作为超过传统铸造。正规铸造已经是一个相当便宜的操作。


First, let me explain the current situation: I'm reading records from a database and putting them in an object for later use; today a question about the database type to C# type conversion (casting?) arose.

Let's see an example:

namespace Test
{
    using System;
    using System.Data;
    using System.Data.SqlClient;

    public enum MyEnum
    {
        FirstValue = 1,
        SecondValue = 2
    }

    public class MyObject
    {
        private String field_a;
        private Byte field_b;
        private MyEnum field_c;

        public MyObject(Int32 object_id)
        {
            using (SqlConnection connection = new SqlConnection("connection_string"))
            {
                connection.Open();

                using (SqlCommand command = connection.CreateCommand())
                {
                    command.CommandText = "sql_query";

                    using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow))
                    {
                        reader.Read();

                        this.field_a = reader["field_a"];
                        this.field_b = reader["field_b"];
                        this.field_c = reader["field_c"];
                    }
                }
            }
        }
    }
}

This is (obviously) failing because the three this.field_x = reader["field_x"]; calls are throwing the Cannot implicitly convert type 'object' to 'xxx'. An explicit conversion exists (are you missing a cast?). compiler error.

To correct this I currently know of two ways (let's use the field_b example): number one is this.field_b = (Byte) reader["field_b"]; and number two is this.field_b = Convert.ToByte(reader["field_b"]);.

The problem with option number one is that DBNull fields are throwing exceptions as the cast is failing (even with nullable types as String), ant the problem with number two is that it's not preserving null values (the Convert.ToString(DBNull) yields a String.Empty), and I can't use them with enums too.

So, after a couple of lookups on the internet and here at StackOverflow, what I came up with is:

public static class Utilities
{
    public static T FromDatabase<T>(Object value) where T: IConvertible
    {
        if (typeof(T).IsEnum == false)
        {
            if (value == null || Convert.IsDBNull(value) == true)
            {
                return default(T);
            }
            else
            {
                return (T) Convert.ChangeType(value, typeof(T));
            }
        }
        else
        {
            if (Enum.IsDefined(typeof(T), value) == false)
            {
                throw new ArgumentOutOfRangeException();
            }

            return (T) Enum.ToObject(typeof(T), value);
        }
    }
}

This way I should handle every case.

Question is: Am I missing something? Am I doing a WOMBAT (Waste Of Money, Brain And Time) as there's a quicker and cleaner way to do it? It's all correct? Profit?

解决方案

If a field allows nulls, don't use regular primitive types. Use the C# nullable type and the as keyword.

int? field_a = reader["field_a"] as int?;
string field_b = reader["field_a"] as string;

Adding a ? to any non-nullable C# type makes it "nullable". Using the as keyword will attempt to cast an object to the specified type. If the cast fails (like it would if the type is DBNull), then the operator returns null.

Note: Another small benefit of using as is that it is slightly faster than normal casting. Since it can also have some downsides, such as making it harder to track bugs if you try to cast as the wrong type, this shouldn't be considered a reason for always using as over traditional casting. Regular casting is already a fairly cheap operation.

这篇关于如何(有效地)将SqlDataReader字段转换(转换)为其对应的c#类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆