[轉][.NET]將DataTable轉成List物件

來源  http://www.dotblogs.com.tw/rainmaker/archive/2013/11/05/126727.aspx

今天看同事分享時,看到他們將DataTable轉成物件時,使用for…each的方式。

雖然有很多的ORM框架可以幫我們做到同樣的效果,但如果手動要做的話,有那些方式呢?

1 //要轉換的物件
2 public class Document
3 {
4     public string CompId { getset; }
5     public string HandleUnit { getset; }
6     public string No { getset; }
7 }

方法1:使用for…each (for…next也可以)

01 //將DataTable轉成List<物件>
02 DataTable dt = new DataTable();
03 dt.Columns.Add("CompId"typeof(string));
04 dt.Columns.Add("HandleUnit"typeof(string));
05 dt.Columns.Add("No"typeof(string));
06 dt.Rows.Add(new object[] {"655""EBS""001" });
07 dt.Rows.Add(new object[] { "655""ODM""002" });
08 dt.Rows.Add(new object[] { "655""OCS""003" });
09
10 //Way 1, for next
11 List<Document> Way1 = new List<Document>();
12 foreach (DataRow dr in dt.Rows)
13 {
14     Document doc = new Document();
15     doc.CompId = dr.Field<string>("CompId");
16     doc.HandleUnit = dr.Field<string>("HandleUnit");
17     doc.No = dr.Field<string>("No");
18     Way1.Add(doc);
19 }

方式2:建立Extension Methods透過Reflection來簡化(參考:fetch datarow to c# object)

01 public static class DataTableExtensions
02 {
03     public static IList<T> ToList<T>(this DataTable table) where T : new()
04     {
05         IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
06         IList<T> result = new List<T>();
07
08         foreach (var row in table.Rows)
09         {
10             var item = CreateItemFromRow<T>((DataRow)row, properties);
11             result.Add(item);
12         }
13
14         return result;
15     }
16
17     public static IList<T> ToList<T>(this DataTable table, Dictionary<stringstring> mappings) where T : new()
18     {
19         IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
20         IList<T> result = new List<T>();
21
22         foreach (var row in table.Rows)
23         {
24             var item = CreateItemFromRow<T>((DataRow)row, properties, mappings);
25             result.Add(item);
26         }
27
28         return result;
29     }
30
31     private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
32     {
33         T item = new T();
34         foreach (var property in properties)
35         {
36             property.SetValue(item, row[property.Name], null);
37         }
38         return item;
39     }
40
41     private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties, Dictionary<stringstring> mappings) where T : new()
42     {
43         T item = new T();
44         foreach (var property in properties)
45         {
46             if (mappings.ContainsKey(property.Name))
47                 property.SetValue(item, row[mappings[property.Name]], null);
48         }
49         return item;
50     }
51 }

方式2.1:如果欄位名稱跟物件屬性名稱相同,則直接對應。

1 DataTable dt2 = new DataTable();
2 dt2.Columns.Add("CompId"typeof(string));
3 dt2.Columns.Add("HandleUnit"typeof(string));
4 dt2.Columns.Add("No"typeof(string));
5 dt2.Rows.Add(new object[] { "655""EBS""001" });
6 dt2.Rows.Add(new object[] { "655""ODM""002" });
7 dt2.Rows.Add(new object[] { "655""OCS""003" });
8 //Way 2, 如果欄位名稱跟屬性一樣,就直接Assign
9 var Wary2 = dt2.ToList<Document>();

方式2.2:如果欄位名稱跟物件屬性名稱不同,則建立Dictionary型態的Mapping物件,如下,

01 DataTable dt3 = new DataTable();
02 dt3.Columns.Add("CompId"typeof(string));
03 dt3.Columns.Add("HandleUnit"typeof(string));
04 dt3.Columns.Add("No"typeof(string));
05 dt3.Rows.Add(new object[] { "655""EBS""001" });
06 dt3.Rows.Add(new object[] { "655""ODM""002" });
07 dt3.Rows.Add(new object[] { "655""OCS""003" });
08 //Way 3, 如果欄位跟屬性不同,就建一個Mapping表
09
10 var mappings = new Dictionary<stringstring>();
11 mappings.Add("CompId""CompId");
12 mappings.Add("HandleUnit""HandleUnit");
13 mappings.Add("No""No");
14 var Way3 = dt3.ToList<Document>(mappings);

相信一定有一堆人會問說,為何要這樣做呢? 為何不使用ORM呢?  為什麼? 為什麼? …..等很多的疑問

同事回說,因為只是針對舊有的系統新增一個小的模組,而目前系統的Table有300多個,時間有限 … So…. 就先這樣搞…

C# 使用 List 達成多維不特定長度的陣列效果

C# 在使用時 array 時,要先宣告陣列大小。
若一開始不確定陣列大小,
想要使用時再動態增加大小,可以使用 List 來達成此效果

例如:
List<string> my1d; // 1維:List 裡面放不確定數量的 stirng
List<List<string>> my2d;// 2維:List 裡面放不確定數量的 List<string>

範例:以 List 做成類似 3維陣列,但每一維度,底下元素個數不固定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
希望達成此效果
Array (
    0 => Array(
            0 => Array("A1", "A2", "A3", "A4"),
            1 => Array("B1", "B2", "B3")
        ),
    1 => Array(
            0 => Array("C1", "C2")
        )
);
*/
List<List<List<string>>> my3d = new List<List<List<string>>>();
List<string> my1d;
List<List<string>> my2d;
//
my2d = new List<List<string>>();
my1d = new List<string>();
my1d.Add("A1");
my1d.Add("A2");
my1d.Add("A3");
my1d.Add("A4");
my2d.Add(my1d);
my1d = new List<string>();
my1d.Add("B1");
my1d.Add("B2");
my1d.Add("B3");
my2d.Add(my1d);
my3d.Add(my2d);
//
my2d = new List<List<string>>();
my1d = new List<string>();
my1d.Add("C1");
my1d.Add("C2");
my2d.Add(my1d);
my3d.Add(my2d);
Console.WriteLine("my3d[0][0][2] = " + my3d[0][0][2]); // my3d[0][0][2] = A3
Console.WriteLine("my3d[0][1][0] = " + my3d[0][1][0]); // my3d[0][1][0] = B1
Console.WriteLine("my3d[1][0][1] = " + my3d[1][0][1]); // my3d[1][0][1] = C2
Console.WriteLine("my3d.Count = " + my3d.Count); // my3d.Count = 2
Console.WriteLine("my3d[0].Count = " + my3d[0].Count); // my3d[0].Count = 2
Console.WriteLine("my3d[1].Count = " + my3d[1].Count); // my3d[1].Count = 1
Console.WriteLine("my3d[0][0].Count = " + my3d[0][0].Count); // my3d[0][0].Count = 4
Console.WriteLine("my3d[0][1].Count = " + my3d[0][1].Count); // my3d[0][1].Count = 3
Console.WriteLine("my3d[1][0].Count = " + my3d[1][0].Count); // my3d[1][0].Count = 2

資料繫結以及Container.DataItem幾種方式與用法,效率分析

靈活的運用資料繫結操作

綁定到簡單屬性:<%#UserName%>
綁定到集合:<asp:ListBox id=”ListBox1″ datasource='<%# myArray%>’ runat=”server”>
綁定到運算式:<%#(class1.property1.ToString() + “,” + class1.property2.ToString())%>
綁定到方法傳回值:<%# GetSafestring(str) %>
綁定到Hashtable:<%# ((DictionaryEntry)Container.DataItem).Key%>
綁定到ArrayList:<%#Container.DataItem %>

 

若陣列裡裡放的是物件則可能要進行必要的轉換後再綁定如:
<%#((物件類型)Container.DataItem).屬性%>

 

綁定到DataView,DataTable,DataSet:
<%#((DataRowView)Container.DataItem)[“欄位名”]%>或
<%#((DataRowView)Container.DataItem).Rows[0][“欄位名”]%>

要格式化則:
<%#string.Format(“格式”,((DataRowView)Container.DataItem)[“欄位名”])%>
<%#DataBinder.Eval(Container.DataItem,”欄位名”,”格式”)%>

 

綁定到DataReader:
<%#((IDataReader)Container.DataItem).欄位名%>

 

當然為了方便一般使用最多的就是DataBinder類的Eval方法了.不過這樣對於同時要綁定大量的資料效率要低一些

 

在綁定資料時經常會用到這個句程式:<%# DataBinder.Eval(Container.DataItem,”xxxx”)%>或者<%# DataBinder.Eval(Container,”DataItem.xxxx”)%>
今天又學到一種,而且微軟也說這種方法的效率要比以上兩種高。
<%# ((DataRowView)Container.DataItem)[“xxxx”]%>

很有用的,這樣可以在前臺頁面做好多事情了。
還要記住要這樣用必須要在前臺頁面導入名稱空間System.Data,否則會建置錯誤資訊。
<%@ Import namespace=”System.Data” %>
這種用法其實和<%# ((DictionaryEntry)Container.DataItem).Key%>是一個道理。

綁定到DataSet、DataTable時:
<%#((System.Data.DataRowView)Container.DataItem)[“欄位名”]%>
<%#((System.Data.DataRowView)Container.DataItem)[索引]%>

綁定到DataReader時:
<%#((System.Data.Common.DbDataRecord)Container.DataItem)[索引]%>
<%#((System.Data.Common.DbDataRecord)Container.DataItem)[“欄位名”]%>
關鍵是Container這個東西,它比較神秘。它的名稱空間是System.ComponentModel。對於它我還需要進一步理解。
初學.NET,現在在看DataGrid控制項,在ItemTemplate顯示資料時,
DataBinder.Eval(Container.DataItem,”Name”)和Container.DataItem(“Name”)有什麼區別?
DataBinder是System.Web裡面的一個靜態類,它提供了Eval方法用於簡化資料繫結運算式的編寫,但是它使用的方式是通過Reflection等開銷比較大的方法來達到易用性,因此其性能並不是最好的。而Container則根本不是任何一個靜態的物件或方法,它是ASP.NET頁面編譯器在資料繫結事件處理常式內部聲明的區域變數,其類型是可以進行資料繫結的控制項的資料容器類型(如在Repeater內部的資料繫結容器叫RepeaterItem),在這些容器類中基本都有DataItem屬性,因此你可以寫Container.DataItem,這個屬性返回的是你正在被綁定的資料來源中的那個資料項目。如果你的資料來源是DataTable,則這個資料項目的類型實際是DataRowView。

C#的 Code Blocks 模式,微軟MSDN的範例

http://msdn.microsoft.com/en-us/library/vstudio/f0111sbh(v=vs.100).aspx
底下為程式碼

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            Response.Write("<br />Page has been posted back.");
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    Hello.<br />
    <asp:Button ID="Button1" runat="server" 
    Text="Click to Post Back" />
    </div>
    </form>
</body>
</html>

[轉]MSSQL(limit) → MYSQL

來源  http://www.dotblogs.com.tw/easonwei/archive/2012/09/24/75008.aspx
最近將MYSQL查詢改成MSSQL
關於查詢限制條件記錄於下:
MYSQL 
1 select from [tablewhere ... LIMIT 123
MSSQL
1 select top 123* from [tablewhere ...
–限制資料筆數(只取前面0~123筆)
–(方法A)效率較好
1 select top 123 *
2  from [user]
3  order by emp_id desc
–(方法B)效率較差
1 select *
2   from (select ROW_NUMBER() over (order by emp_id asc) rownum,
3   
4  from [user] ) as yourselect
5   where rownum between and 123
6    order by emp_id desc
–用來做分頁查詢(只取第123~150筆)
–(方法C)效率較好
1 select *
2   from (  select ROW_NUMBER() over (order by emp_id asc) rownum,
3  *
4   from [user] ) as yourselect
5   where rownum between 123 and 150
6  order by emp_id desc
–(方法D)效率較差
1 SELECT TOP 150 *
2   FROM [userWHERE user_id_seq NOT IN
3   SELECT TOP 123 user_id_seq FROM [userORDER BY user_id_seq ASC )
4   ORDER BY emp_id ASC

[轉]ASP.NET MVC3 Razor 初心者容易遇到的問題

http://demo.tc/Post/679

在 ASP.NET MVC 3 中增加了一種新的 視圖引擎( View Engine )優點相當的多因此 demo 相信如果要寫 ASP.NET MVC 3 的朋友絕大多數都會選擇使用 Razor 但因為寫法改變,剛開始可能是會十分不習慣,甚至一些很簡單的東西還要 Try 很多次才會成功,因此 demo 特別整理了一下,我寫 demo小鋪時有停頓的地方,期望有需要的網友可以更快的接觸 Razor 這相當優良的 視圖引擎( View Engine )

Ads by Yahoo!

  • 雲端進銷存會計庫存管理系統

    Web-ACC.com

    跨平台且可以使用智慧型手機登錄的進銷存管理系統, 線上免費試用不需安裝APP

  • 台塑商業流程管理BPM方案

    www.efpg.com.tw

    FPG-Flow可整合ERP內建基本表單,彈性設計,強化bpm環境支援執行力。

  • 檔案版本:3
  • 最後更新:2012/8/14 上午 10:41:29
  • 2011-06-13:增加電子郵件與@() 的用法說明

●基本寫法介紹

為了讓文章更清楚這裡先假設以下輸出值

  1. Model.Content=“<a href=’http://demo.tc’ >demo小鋪</a>”
  2. item.Key=“<span>IsKey</span>”
  3. item.Value=“<span>IsValue</span>”

Razor Aspx
程式碼區塊:無輸出
@{
    int a = 123;
    string b = "demoshop";
 }
<%
    int a = 123;
    string b = "demoshop";
%>
HTML Encoded:<a href=’http://demo.tc’ >demo小鋪</a>
<div>
    @Model.Content
</div>
<div>
    <%:Model.Content %>
</div>
HTML Unencoded:demo小鋪
<div>
    @Html.Raw(Model.Content)
</div>
<div>
    <%=Model.Content %>
</div>
混合程式碼:<span>IsKey</span>
@foreach (var item in collection)
{
    <span>@item.Key</span>
}
<%foreach (var item in collection)
    {%>
        <span><%:item.Key %></span>
<%%>
混合程式碼:我是純文字 <span>IsValue</span>
@foreach (var item in collection)
{
    <text>我是純文字</text> @item.Value
}
<%foreach (var item in collection)
    {%>
        我是純文字 <%:item.Key %>
<%%>
混合程式碼:我是純文字 <span>IsValue</span>
@foreach (var item in collection)
{
    @:我是純文字 @item.Value
}
<%foreach (var item in collection)
    {%>
        我是純文字 <%:item.Key %>
<%%>
混合程式碼:目前是第 0. 目前是第 1. 目前是第 2.
@for (int i = 0; i < 3; i++)
{
    @:目前是第 @i. 
}
<%for (int i = 0; i < 3; i++)
  {%>
      目前是第<%=%>.
<%%>
三元運算子:<a href=’http://demo.tc’ >demo小鋪</a>
@(Model.Content == "" ? "沒貨" : Model.Content)

<%:Model.Content==""?"沒貨": Model.Content%>
註解:無輸出
@*你看不到我*@
<%--你看不到我--%>

以上部分表格參考C# Razor Syntax Quick Reference


●神奇的 [at] 符號

@念法是 [at] ,台灣俗稱小老鼠,在 Razor 中它有舉足輕重的用處,因為同時列在上表 demo 覺得有點亂因此在給它一個區塊來放它,Razor 很有趣!基本上它會判斷空白字元與斷行符號

●比如說我需要輸出 item.Key和item.Value 的值可以有以下的寫法

@item.Key@item.Value

@(item.Key + item.Value)

●如果你需要 Unencoded

@:item.Key @item.Value

●如果要輸出 I @ Taiwan

I @@ Taiwan

●email 的輸出根本不需要有任何調整

test@test.com

demo廢言前文有提到 Razor 會判斷空白字元和斷行符號,也因為 Email 的 @ 前後都有字所以會很聰明的認定它為字串,並不會當變數看,再來看下面一個範例會更清楚

依據上面的範例今天我們要輸出 demo歡迎登入的字樣,網友們可能會這樣寫

@User.Identity.Name 歡迎登入 //變數和文字中利用一個半型空白來斷開

但這有可能是我們不想要的效果,那就可以利用 @() 包住變數將它改寫為

@(User.Identity.Name)歡迎登入

就會是黏在一起的文字了


●同場加映HTML5 支援

在 HTML5 中有一個很不錯的資料記錄標籤 data-xxx ,因為使用他不需要自行定義標籤因此 demo 還滿喜歡的而且利用 jQuery 就可以相當簡單的把 這標籤的值取出( 官方 API )但是如果你想在 ASP.NET MVC3 中使用需要調整一下寫法

@Html.TextBoxFor(model => model.Key, new {data_test="500" })

必須要使用底線,編譯的時候會自動轉換

參考文章

[轉帖][ASP.NET & jQuery]使用jQuery的Ajax存取資料(ashx,aspx,asmx)

來源:http://www.dotblogs.com.tw/hatelove/archive/2009/12/22/jqueryajax.aspx

前言

之前沒太多xmlHttpRequest與撰寫CallBack javascript的經驗,
一開始寫程式,就被AJAX.NET的UpdatePanel養壞了。

慢慢瞭解到UpdatePanel只是個偽裝的ajax,背後付出的effort仍然相當龐大後,
才慢慢的想去瞭解ajax該如何撰寫。

想要擺脫AutoPostBack付出的龐大成本,javascript與ajax的能力就一定要能養成。

這邊搭配jQuery的ajax功能,來示範一下在ASP.NET上的作法。

Play it

這邊範例的需求是,我們有兩個textbox,一個是ID,一個是Name,
當輸入ID改變時,要帶出Name的資料。(學會之後,就可以擺脫AutoPostBack=true,Text_Changed的方式啦…)

在這裡我把ID帶Name的程式碼,分別寫在三種檔案上來處理。

  1. .ashx(泛型處理常式)
  2. .aspx(一般網頁頁面)
  3. .asmx(Web Service)

為方便各位下載sample code後可以直接跑,
這邊的Name,就是取first name,加上js傳過來的第二個參數MiddleName:『middle』字樣,
last name的部分,則是測試Session值能否被Server端讀取到,所以再補上Session的值『91』來紀念代表從server端回傳的Name。

也就是ajax return回來的值是:畫面上輸入的first name+『middle』+ Session[“LastName”]
接著,讓我們繼續看下去。

  1. .ashx
    • 先新增一個泛型處理常式檔案,記得引用System.Web.SessionState與實作IReadOnlySessionState,我們才能在程式碼裡面讀到Session。
    • 接參數的部分,使用context.Request.Form[“參數名稱]
    • 最後return的值,則是使用context.Response.Write(回傳值)
      ashx
  2. .aspx
    • 先新增一個.aspx,接著只保留第一行<%@ Page %>那行
    • 在Page_Load的事件撰寫要處理的程式碼
    • 接參數的部分,使用的是Request.Form[“參數名稱]
    • 最後return的值,則是直接Response.Write(回傳值)
      aspx
  3. .asmx
    • 先新增一個.asmx,接著把[System.Web.Script.Services.ScriptService]取消註解
    • 新增一個public的method,叫做GetFullName,method上頭加上[WebMethod(EnableSession=true)],才能使用Session
    • return的資料直接return即可,雖然return的型別是string,但是javascript實際接到的是xml格式的字串
      asmx

有了這三種處理ID回傳Name的程式後,
來看看我們的頁面要怎麼撰寫。

網頁的部分,用三組來當試驗:

01 <body>
02     <form id="form1" runat="server">
03     <div>
04         .ashx: first name<asp:TextBox ID="txtIDbyAshx" runat="server"></asp:TextBox>
05         full name<asp:TextBox ID="txtNamebyAshx" runat="server"></asp:TextBox><br />
06         
07         .aspx: first name<asp:TextBox ID="txtIDbyAspx" runat="server"></asp:TextBox>
08         full name<asp:TextBox ID="txtNamebyAspx" runat="server"></asp:TextBox><br />
09         
10         .ashx: first name<asp:TextBox ID="txtIDbyAsmx" runat="server"></asp:TextBox>
11         full name<asp:TextBox ID="txtNamebyAsmx" runat="server"></asp:TextBox><br />
12     </div>
13     </form>
14 </body>

接著使用jQuery的ajax功能,注意的地方:

  1. 註冊在change事件
  2. ajax option:
    • type:使用post
    • url的部分,web service需加上method名稱
    • 傳入參數的部分,可用json,或一般字串使用『&』串接,如同一般的post或QueryString
    • ajax成功的話,會進入success,失敗會進入error
    • 成功回傳的字串,在success的function(回傳值)
    • web service回傳為XML格式,需自行parse使用

jQuery

結論

ajax的能力未來一定得具備,因為不管是一般的html、畫面冗重的Web form、或是ASP.NET MVC,
要等待Post的過程,對User來說都是種折磨。

既然沒有多難,就順手把它學起來吧!

In 91 it!!

Sample Code: jQueryAjax.zip

ASP.NET C# 3個執行SQL的方法說明

ExecuteNonQuery()

用法:ExecuteNonQuery用來執行INSERT、UPDATE、DELETE和其他沒有返回值得SQL命令。例如:CREATE DATABASE 和 CREATE TABLE 命令。

當使用 INSERT、UPDATE、DELETE時,ExecuteNonQuery返回被命令影響的行數。若是用在對其他命令,則返回-1。

ExecuteScalar()

用法1:ExecuteScalar 執行一個SQL命令返回結果集的第一列的第一行。它經常用來執行SQL的COUNT、AVG、MIN、MAX 和 SUM 函數,這些函數都是返回單行單列的結果集。

‘注意:’ExecuteScalar 一般返回一個Object類型,因此必須把它轉換為強類型。如果轉換不正確,.NET框架就會引發 InvalidCastException異常。

用法2:ExecuteScalar 的另一個普遍的用法是從資料庫中檢索BLOB(二進位大物件)。下面的例子從Pubs資料庫的Pub_Info表的Logo欄位中檢索圖像,並把他封裝到一個點陣圖中。

MemoryStream stream = new MemoryStream();

SqlConnection conn = new SqlConnection(“連線字串”);

try
{
conn.open();
SqlCommand cmd = new SqlCommand(“SELECT logo FROM pub_info WHERE pub_id=’0736′”, conn);
byte[] blob = (byte[]) cmd.ExecuteScalar();
stream.Write(blob, 0, blob.Length);
Bitmap bitmap = new Bitmap(stream);

// TODO:使用點陣圖
bitmap.Dispose();
}
catch(SqlException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
stream.Close();
conn.Close();
}

用法3:您也許對如何把BLOB寫入資料庫感興趣,答案是在包裝了INSERT命令(該命令中包含了類型為byte[]的輸入參數)的命令物件上調用ExcuteNonQuery方法。下面例子在Pubs資料庫的Pub_Info表中插入一條記錄,記錄的Logo欄位包含一個BLOB。

— 定義和初始化blob變數
FileStream stream = new FileStream(“Logo.jpg”, FileMode.Open);
byte[] blob = new byte[stream.Length];
stream.Read(blob, 0, (int) stream.Length);
stream.Close();
SqlConnection conn = new SqlConnection(“連線字串”);

try
{
conn.open();
SqlCommand cmd = new SqlCommand(“INSERT INTO pub_info(pub_id, logo) VALUES(‘9937’, @logo)”, conn);
cmd.Parameters.Add(“@logo”, blob);
cmd.ExecuteNonQuery();
}
catch(SqlException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
stream.Close();
conn.Close();
}

ExecuteReader()

用法:ExecuteReader 方法存在的目的只有一個:盡可能快地對資料庫進行查詢並得到結果。ExecuteReader 返回一個DataReader物件:如果在SqlCommand物件中調用,則返回SqlDataReader;如果在OleDbCommand物件中調用,返回的是OleDbDataReader。可以調用DataReader的方法和屬性反覆運算處理結果集。它是一個快速枚舉資料庫查詢結果的機制,是唯讀、只進的。對SqlDataReader.Read的每次調用都會從結果集中返回一行。