通过DataReader获取多个结果集

本文介绍如何使用ADO.NET的DataReader通过NextResult方法处理多个结果集,实现T-SQL批处理,包括实体类定义、数据实体转换及前台调用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们知道,ado.net的DataReader提供一种从数据库读取行的只进流的方式。通常情况下,我们都是针对一个结果集进行处理。其实通过DataReader的NextResult方法,我们可以批处理T-SQL,也就是可以获取处理两个或者多个结果集。下面通过一个简单的示例,来简单说明一下这个功能。
1、数据表
我们还是沿用这一篇里的Person表。在Person表里,我们定义了自增长的Id,姓、名、身高和体重,它们对应的字段和实体里的属性命名是一样的。

2、实体类


    
public   class  Person
    {
        
public   int  Id {  get set ; }
        
public   string  FirstName {  get set ; }
        
public   string  LastName {  get set ; }
        
public   double  Weight {  get set ; }
        
public   double  Height {  get set ; }

        
///   <summary>
        
///  总记录数
        
///   </summary>
         public   long  TotalCount {  get set ; }
    }

需要说明的是,TotalCount属性是我们自己根据统计需要,添加的用来统计符合条件的人的总记录数,并不是Person表的一个实际字段。

3、数据实体转换

代码
  public   class  SqlHelper
    {
        
private   const   string  strSqlCon  =   @" Data Source=.\sqlexpress; Initial Catalog=TestDb; User Id=sa; Password=123456; " ;

        
///   <summary>
        
///  数据表项转换为对应实体 (操作两个结果集 有总记录数)
        
///   </summary>
        
///   <typeparam name="T"></typeparam>
        
///   <param name="objType"></param>
        
///   <param name="strSelectSql"></param>
        
///   <returns></returns>
         public   static  IList < T >  Select < T > (Type objType,  string  strSelectSql)  where  T :  class new ()
        {
            IList
< T >  listModels  =   new  List < T > ();
            
using  (SqlConnection sqlConn  =   new  SqlConnection(strSqlCon))
            {
                sqlConn.Open();
                SqlCommand cmd 
=   new  SqlCommand();
                cmd.Connection 
=  sqlConn;
                cmd.CommandText 
=  strSelectSql;
                IDataReader rdr 
=  cmd.ExecuteReader();
                Hashtable htColumns 
=  CreateHashColumnName(rdr);

                
while  (rdr.Read())
                {
                    Object obj 
=  Activator.CreateInstance(objType);
                    PropertyInfo[] properties 
=  objType.GetProperties();
                    
foreach  (PropertyInfo propInfo  in  properties)
                    {
                        
if  (htColumns.Contains(propInfo.Name.ToUpper())  ==   false )
                        {
                            
continue ;
                        }
                        
int  index  =  rdr.GetOrdinal(propInfo.Name);
                        
if  (index  >   - 1   &&  rdr.GetValue(index)  !=  System.DBNull.Value)
                            propInfo.SetValue(obj, rdr.GetValue(index), 
null );
                    }
                    T model 
=   default (T);
                    model 
=  obj  as  T;
                    listModels.Add(model);
                }

                
bool  isNext  =  rdr.NextResult(); // 前进到下一个结果集
                htColumns  =  CreateHashColumnName(rdr); // 改变hashtable的对应列名
                 while  (rdr.Read()  &&  isNext)
                {
                    
for  ( int  i  =   0 ; i  <  listModels.Count; i ++ )
                    {
                        PropertyInfo[] props 
=  listModels[i].GetType().GetProperties();
                        
foreach  (PropertyInfo pi  in  props)
                        {
                            
if  (htColumns.Contains(pi.Name.ToUpper())) // 取总记录数
                            {
                                
int  index  =  rdr.GetOrdinal(pi.Name);
                                
if  (index  >   - 1   &&  rdr.GetValue(index)  !=  System.DBNull.Value)
                                    pi.SetValue(listModels[i], rdr.GetValue(index), 
null );
                                
break ; // 根据实际情况确定break需不需要注释掉
                            }
                        }
                    }
                }
            }
            
return  listModels;
        }

        
private   static  Hashtable CreateHashColumnName(IDataReader rdr)
        {
            
int  len  =  rdr.FieldCount;
            Hashtable ht 
=   new  Hashtable(len);
            
for  ( int  i  =   0 ; i  <  len; i ++ )
            {
                
string  columnName  =  rdr.GetName(i).ToUpper();  // 不区分大小写
                 string  columnRealName  =  rdr.GetName(i);
                
if  (ht.ContainsKey(columnName)  ==   false )
                {
                    ht.Add(columnName, columnRealName);
                }
            }
            
return  ht;
        }

    }

上面的代码中,注释写的很清楚,通过NextResult方法后,我们再次获取结果集的列(示例中保持在hashtable里),利用第一次获得结果集的方法和原理,给实体赋值。

4、前台调用
很简单,通过一个带分号的sql语句,获得一个实体集合。

代码
     // 批量sql语句 以;隔开
             string  sql  =   " SELECT TOP 10 [Id] ,[FirstName],[LastName],[Weight],[Height] FROM Person (NOLOCK); SELECT COUNT(Id) AS TotalCount FROM Person (NOLOCK)  " ;
            IList
< Person >  listPersons  =  SqlHelper.Select < Person > ( typeof (Person), sql); // 操作两个结果集

 

有图有真相:



从图中我们可以清楚地看到,测试数据库里的总人数是1999918人。

最后,请教最近使用linq2sql一点困扰我的地方:很多人津津乐道的Skip...Take分页(本质上据说就是二次top),好像无法直接取得总记录数(TotalCount),但是正常项目中都会通过总记录数确定分页效果。除了直接通过linq查询取Count之外,不知道大家有没有其他更好的方法,比如窗口函数row number,或者就像本文所表达的那样,批处理一次查询就搞定的那种?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值