正确返回字段填充的SQL DataRow的方法

时间:2011-07-22 16:32:40

标签: c# sql

我有以下场景,我一直用它来从SQL数据库返回一行。在我返回数据之后,我只是用它来填充我的网络表单上的字段。

示例数据库类:

public class DBAccess
{
    public DataTable ReturnContactInfo(int userID)
    {
        // executes a stored procedure, populates a datatable, then returns it
    }
}

使用类填充理论客户名称字段的示例:

protected void Page_Load(object sender, EventArgs e)
{
    if(!isPostBack)
    {
        DBAccess db = new DBAccess();
        DataTable dt =  db.ReturnContactInfo(1);
        if (dt.Rows.Count > 0)
        {
           customerName.Text = Convert.ToString(dt.Rows[0]["customerName"]);
        }
     }
}

是否有更好或更有效的方法(“这”返回单个数据行以从中提取数据)?这种方法当然有效,但是当我总是只需要处理索引0处的行时,必须键入dt.Rows [0] [string]有点麻烦。请记住我喜欢能够将提取的所有数据层内容保存到单个类中。哪(根据我的理解)意味着我不能使用SqlDataReader,因为它必须在完成后关闭,所以我不能从我的数据层类返回它。

3 个答案:

答案 0 :(得分:4)

使用您想要的成员定义一个类作为属性。然后填充并返回该对象。你可以使用像“dapper”这样的工具来实现这一点:

public Customer GetCustomer(int id)
{
     return connection.Query<Customer>("getCustomer",
         new {id}, // <=== param
         commandType: CommandType.StoredProcedure).Single();
}

然后:

var cust = GetCustomer(12345);
string name = cust.Name;

现在:

  • 很明显我们有一个单一的对象
  • 对象上的成员很明显且类型很好
  • 您可以避免DataTable的大量开销

答案 1 :(得分:0)

如果您知道只返回1行,为什么不返回DataRow而不是DataTable?

答案 2 :(得分:0)

我写了一个代码生成器,它生成我的数据访问代码,每个存储过程一个类。其中一个选项是您可以指定其结果集由单行组成。用法很简单:生成的代码通过包装器方法调用,该方法强制执行使用契约所需的任何约束,因此:

    public DataRow GetPatientData( int patientID )
    {
        dbo_GetPatientData67 sp = new dbo_GetPatientData( CONNECT_STRING_ID ) ;
        int                  rc = sp.Exec( patientID ) ;
        DataRow              dr = sp.ResultSet ;

        if ( dr == null ) throw new InvalidOperationException("nothing returned from stored procedure.") ;
        return dr ;
    }

以下是数据访问代码的基本要素:

/* generated code. do not change -- generated code */
public class dbo_GetPatientData
{

  public int     ReturnCode { get ; private set ; }
  public DataRow ResultSet { get ; private set ; }

  public int Exec(  int? @iPatientID )
  {
    using ( SqlConnection  conn = new SqlConnection( this._connectString ) )
    using ( SqlCommand     cmd  = conn.CreateCommand() )
    using ( SqlDataAdapter sda  = new SqlDataAdapter( cmd ) )
    {
      cmd.CommandText = STORED_PROCEDURE_NAME ;
      cmd.CommandType = CommandType.StoredProcedure ;

      //
      // 1. @iPatientID
      //
      // required
        SqlParameter p1 = new SqlParameter( @"@iPatientID" , SqlDbType.Int ) ;
        if ( @iPatientID == null )
        {
          p1.Value = System.DBNull.Value ;
        }
        else
        {
          p1.Value = @iPatientID ;
        }
        cmd.Parameters.Add( p1 ) ;

      // add return code parameter
      SqlParameter pReturnCode = new SqlParameter() ;
      pReturnCode.SqlDbType = System.Data.SqlDbType.Int ;
      pReturnCode.Direction = System.Data.ParameterDirection.ReturnValue ;
      cmd.Parameters.Add( pReturnCode ) ;

      DataSet ds = new DataSet() ;

      conn.Open() ;
      sda.Fill( ds ) ;
      conn.Close() ;

      DataTable dt    = ( ds.Tables.Count > 0 ? ds.Tables[0] : null ) ;
      this.ResultSet  = ( dt != null && dt.Rows.Count > 0 ? dt.Rows[0] : null ) ;
      this.ReturnCode = (int) pReturnCode.Value ;


    }

    return this.ReturnCode ;

  }

}

现在你只有一个DataRow来处理(但是,如果你需要它,它的相关DataTable / DataSet等仍然存在)。向DataRow类添加扩展方法消除了将每列向下转换为正确类型的繁琐工作。我宁愿写:

int? x = dr.CastAsIntNullable( "myColumn" ) ;

比通常的样板。

public static class DataRowExtensions
{

    #region downcast to DateTime

    public static DateTime CastAsDateTime( this DataRow row , int index )
    {
        return toDateTime( row[index] ) ;
    }
    public static DateTime CastAsDateTime( this DataRow row , string columnName )
    {
        return toDateTime( row[columnName] ) ;
    }

    public static DateTime? CastAsDateTimeNullable( this DataRow row , int index )
    {
        return toDateTimeNullable( row[index] );
    }
    public static DateTime? CastAsDateTimeNullable( this DataRow row , string columnName )
    {
        return toDateTimeNullable( row[columnName] ) ;
    }

    #region conversion helpers

    private static DateTime toDateTime( object o )
    {
        DateTime value = (DateTime)o;
        return value;
    }

    private static DateTime? toDateTimeNullable( object o )
    {
        bool  hasValue = !( o is DBNull );
        DateTime? value    = ( hasValue ? (DateTime?) o : (DateTime?) null ) ;
        return value;
    }

    #endregion

    #endregion downcast to DateTime

    #region downcast to byte[]

    public static byte[] CastAsByteArray( this DataRow row , int index )
    {
        return toByteArray( row[index] );
    }
    public static byte[] CastAsByteArray( this DataRow row , string columnName )
    {
        return toByteArray( row[columnName] );
    }

    #region conversion helpers

    private static byte[] toByteArray( object o )
    {
        bool   hasValue = !( o is DBNull );
        byte[] value    = ( hasValue ? (byte[]) o : (byte[]) null ) ;
        return value;
    }

    #endregion

    #endregion downcast to Byte[]

    #region downcast to int

    public static int CastAsInt( this DataRow row , int index )
    {
        return toInt( row[index] ) ;
    }
    public static int CastAsInt( this DataRow row , string columnName )
    {
        return toInt( row[columnName] ) ;
    }

    public static int? CastAsIntNullable( this DataRow row , int index )
    {
        return toIntNullable( row[index] );
    }
    public static int? CastAsIntNullable( this DataRow row , string columnName )
    {
        return toIntNullable( row[columnName] ) ;
    }

    #region conversion helpers

    private static int toInt( object o )
    {
        int value = (int)o;
        return value;
    }

    private static int? toIntNullable( object o )
    {
        bool hasValue = !( o is DBNull );
        int? value    = ( hasValue ? (int?) o : (int?) null ) ;
        return value;
    }

    #endregion

    #endregion downcast to int

    #region downcast to decimal

    public static decimal CastAsDecimal( this DataRow row , int index )
    {
        return toDecimal( row[index] ) ;
    }
    public static decimal CastAsDecimal( this DataRow row , string columnName )
    {
        return toDecimal( row[columnName] ) ;
    }

    public static decimal? CastAsDecimalNullable( this DataRow row , int index )
    {
        return toDecimalNullable( row[index] );
    }
    public static decimal? CastAsDecimalNullable( this DataRow row , string columnName )
    {
        return toDecimalNullable( row[columnName] ) ;
    }

    #region conversion helpers

    private static decimal toDecimal( object o )
    {
        decimal value = (decimal)o;
        return value;
    }

    private static decimal? toDecimalNullable( object o )
    {
        bool     hasValue = !( o is DBNull );
        decimal? value    = ( hasValue ? (decimal?) o : (decimal?) null ) ;
        return value;
    }

    #endregion

    #endregion downcast to decimal


    #region downcast to double

    public static double CastAsDouble( this DataRow row , int index )
    {
        return toDouble( row[index] ) ;
    }
    public static double CastAsDouble( this DataRow row , string columnName )
    {
        return toDouble( row[columnName] ) ;
    }

    public static double? CastAsDoubleNullable( this DataRow row , int index )
    {
        return toDoubleNullable( row[index] );
    }
    public static double? CastAsDoubleNullable( this DataRow row , string columnName )
    {
        return toDoubleNullable( row[columnName] ) ;
    }

    #region conversion helpers

    private static double toDouble( object o )
    {
        double value = (double)o;
        return value;
    }

    private static double? toDoubleNullable( object o )
    {
        bool     hasValue = !( o is DBNull );
        double? value    = ( hasValue ? (double?) o : (double?) null ) ;
        return value;
    }

    #endregion

    #endregion downcast to double

    #region downcast to bool

    public static bool CastAsBool( this DataRow row , int index )
    {
        return toBool( row[index] ) ;
    }
    public static bool CastAsBool( this DataRow row , string columnName )
    {
        return toBool( row[columnName] ) ;
    }

    public static bool? CastAsBoolNullable( this DataRow row , int index )
    {
        return toBoolNullable( row[index] );
    }
    public static bool? CastAsBoolNullable( this DataRow row , string columnName )
    {
        return toBoolNullable( row[columnName] ) ;
    }

    #region conversion helpers

    private static bool toBool( object o )
    {
        bool value = (bool)o;
        return value;
    }

    private static bool? toBoolNullable( object o )
    {
        bool  hasValue = !( o is DBNull );
        bool? value    = ( hasValue ? (bool?) o : (bool?) null ) ;
        return value;
    }

    #endregion

    #endregion downcast to bool

    #region downcast to string

    public static string CastAsString( this DataRow row , int index )
    {
        return toString( row[index] );
    }
    public static string CastAsString( this DataRow row , string columnName )
    {
        return toString( row[columnName] );
    }

    #region conversion helpers

    private static string toString( object o )
    {
        bool   hasValue = !( o is DBNull );
        string value    = ( hasValue ? (string) o : (string) null ) ;
        return value;
    }

    #endregion

    #endregion downcast to string

}