1

假设我有一个像这样的自定义类:

public class Customer    
{        
 public int CustomerID { get; set; }        
 public string CompanyName { get; set; }        
 public string BusinessAddress { get; set; }        
 public string Phone { get; set; } 
 public int ParentID { get; set; } 
}

我使用数据读取器从数据库创建自定义对象。前任:

  while (dr.Read())
  {
    listCustomers.Add(new Customer(
          Convert.ToInt32(dr["CustomerID"]),
          Convert.ToString(dr["CompanyName"]),
          Convert.ToString(dr["BusinessAddress"]),
          Convert.ToString(dr["Phone"]),
          Convert.ToInt32(dr["ParentID"]),
)

ParentID 在数据库中可以为空(我无法更改)。当它为空时,转换显然会失败。

我应该如何处理从数据库中检索到的空值来填充我的业务对象?在我的自定义类中使用 Nullable 类型会是一种很好的做法吗?还有其他提示吗?

4

6 回答 6

6

绝对地。可空类型非常好。否则,您将不得不想出一些愚蠢的约定 a-la “当 ParentID 为 -1 时,这意味着Customer没有父母”。可空类型强制执行此“设计”:如果没有父级,ParentID则为null.

至于水合对象,请考虑使用 ORM 工具(例如NHibernateBLToolkit),因为您真的不想花费 50% 的开发时间来编写 SQL 查询并从数据读取器填充对象

于 2009-10-06T10:29:48.357 回答
3

在业务对象中使用可为空的类型。然后,您可以使用这样的通用辅助方法从数据库中提取可为空的字段。

public static T? GetValue<T>(IDataRecord record, string columnName)
    where T : struct
{
    int columnIndex = record.GetOrdinal(columnName);
    if (record.IsDBNull(columnIndex))
        return null;
    else
        return (T)Convert.ChangeType(record[columnIndex], typeof(T));
}

因此,如果您ParentId被声明为int?在加载行时会执行以下操作。

obj.ParentId = GetValue<int>(dr, "ParentId");
于 2009-10-06T10:52:12.047 回答
2

添加这样的助手怎么样:

    static string safeGetStringFromDB( IDataReader dr, string strField )
    {
        int nIndex = dr.GetOrdinal( strField );
        if ( dr.IsDBNull( nIndex ) )
            return string.Empty;
        return dr.GetString( nIndex );
    }
于 2009-10-06T10:31:38.680 回答
2

可空类型适用于可空字段。

用三元处理任务:-

ParentID = ( dr["ParentID"] is DBNull ) ? null : (int)dr["ParentID"];

此外,如果您知道底层 db 字段是什么以及它们的 .NET 表示形式,则不需要使用 Convert。

我将 convert 的使用限制在我知道类型不同的情况下(比如 int 到 string )。

当我知道 .NET 对应的类型时,我将简单地转换:-

listCustomers.Add(new Customer(
          (int)dr["CustomerID"],
          (string)dr["CompanyName"],
          (string)dr["BusinessAddress"],
          (string)dr["Phone"],
          ( dr["ParentID"] is DBNull ) ? null : (int)dr["ParentID"]));

最后,在使用可空类型时,请注意重载方法可能是一个潜在问题。

考虑以下示例:-

public void Populate( int? facilityId, string name, bool? somethingElse )...
public void Populate( string facilityCode, string name, bool? somethingElse )...

相同数量的参数,所有参数都可能为空。当第一个参数为空时,您可能会对编译器最终选择的解释感到惊讶。无论如何,之前已经抓住了我。

于 2009-10-06T10:45:35.593 回答
1

您可以创建这样的辅助方法:

        static T Map<T>(object obj, Func<object, T> map, T def)
    {
        if (obj != null)
        {
            return map(obj);
        }
        return def;
    }

    static T Map<T>(object obj, Func<object, T> map)
    {
        return Map<T>(obj, map, default(T));
    }

并像这样使用它们:

            object o = 1;
        var t = Map(o, Convert.ToInt32, 0); // with default value
        var t2 = Map(o, Convert.ToInt32); // or without default value
于 2009-10-06T10:32:12.593 回答
0

ParentID 是您班级中的一个字符串,您正在将其转换为 Int32。

但除此之外:您了解数据库,因此您知道哪些字段可以为空。我也会让数据对象中的所有这些字段都可以为空,因为在我看来,这是尽可能接近数据库建模的最佳方式。

于 2009-10-06T10:32:28.350 回答