通過DataReader擷取多個結果集

來源:互聯網
上載者:User

我們知道,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,或者就像本文所表達的那樣,批處理一次查詢就搞定的那種?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.