天天看點

asp.net學習之ado.net(連接配接模式通路)

   ado.net架構支援兩種模式的資料通路: 連接配接模式(Connected)和非連接配接模式(disconnected)。這一節介紹如何使用連接配接模式通路資料庫中的資料,利用ADO.NET中的Connection,Command,DataReader來擷取和修改資料庫中的資料

     連接配接模式要使用到的三個核心類:

     ● IDBConnection : 表示資料源的連接配接,所有Connection類的基類

        SqlConnection實作了IDBConnection接口,用來與SQL Server資料源進行連接配接

     ● DBCommand  : 表示所有Command類的基類

        SqlCommand實作了IDBCommand接口,與來對SQL Server資料庫執行的一個 Transact-SQL 語句或存儲過程

     ● DataReader : 所有DataReader類的基類

        SqlDataReader實作了IDataReader接口,提供一種從 SQL Server 資料庫讀取行的隻進流的方式。

     如果要連接配接到微軟SQL Server資料庫,盡量使用SqlClient命名空間中的SqlConnection,SqlCommand,SqlDataReader類,如果與Oracle資料庫通信,應該使用OracleClient命名空間的類;與其它資料庫進行通信,就應該使用OleDB或ODBC命名空間的類。

圖1: DbConnection與DbCommand的關系圖如下所示:

asp.net學習之ado.net(連接配接模式通路)

例1: 一個簡單的連接配接資料庫查詢的例子

=== App_Code\DawnDataObject.cs ===

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

Code

namespace  DawnDataObject

{

    public class Movies  // 資料實體對象

    {

        public static readonly string _connectionString;  // 連接配接資料庫字元串為靜态成員,每個執行個體共享。

        static Movies(){

            _connectionString = WebConfigurationManager.ConnectionStrings["DawnEnterpriseDBConnectionString"].

                ConnectionString;

        }

        private string _title;

        private string _director;

        // Movies類中包括的屬性有Title、Director

        public string Title{

            get { return _title; }

            set { _title = value; }

        public string Director {

            get { return _director; }

            set { _director = value; }

        // Movies類中的GetAll方法傳回一個List對象,該對象可以被GridView等控件做為資料源綁定

        public List<Movies> GetAll()

        {

            List<Movies> result = new List<Movies>();

            SqlConnection conn = new SqlConnection(_connectionString);

            SqlCommand comm = new SqlCommand("select Title,Director from Movies", conn);

            using(conn){  // using關鍵字指定了conn一旦離開這個代碼段,自動調用其Dispose函數

                conn.Open();

                SqlDataReader reader = comm.ExecuteReader();

                while(reader.Read()){

                    Movies newmovie = new Movies();

                    newmovie._title = (string)reader["Title"];

                    newmovie._director = (string)reader["Director"];

                    result.Add(newmovie);

                }

                return result;

            }

    }

}

=== Movies.aspx ===

<asp:GridView ID="GridView1" runat="server" DataSourceID="ObjectDataSource1" />

<asp:ObjectDataSource ID="ObjectDataSource1" TypeName="DawnDataObject.Movies" SelectMethod="GetAll" runat="server" />

   Connection對象表示資料源的連接配接,執行個體化Connection對象時,需要向構造函數傳遞一個連接配接字元串。連接配接字元串包含了連接配接到資料源所需要的位置和安全認證資訊

   Connection對象也提供了相應的方法對資料庫進行打開和關閉操作;提供了相應的屬性确認資料庫的狀态。

   2.1 連接配接字元串

        一個最普通的連接配接字元串如下所示:

    string _connectionString = "Data Source=(LOCAL);Initial Catalog=DawnEnterpriseDB;User ID=sa;Password=*****";

    SqlConnection conn = new SqlConnection(_connectionSring);   // 可以在建立SqlConnection對象時把連接配接字元串傳遞給構造參數

       也可以使用Connection對象的ConnectionString屬性來擷取或設定用于打開 SQL Server 資料庫的字元串

    string connString = conn.ConnectionString;

    conn.ConnectionString = "Persist Security Info=False;Integrated Security=true;Initial Catalog=Northwind;server=(local)";

       ado.net提供了相應的DbConnectionStringBuilder類來管理資料庫連接配接字元串。相對應的,sqlClient命名空間中就包含了一個SqlConnectionStringBuilder類。

例2:使用SqlConnectionStringBuilder類管理資料庫連接配接字元串

SqlConnectionStringBuilder connstrBuilder = new SqlConnectionStringBuilder();

connstrBuilder.DataSource = "(local)";

connstrBuilder.InitialCatalog = "Test";

connstrBuilder.IntegratedSecurity = true;

using(SqlConnection testConn = new SqlConnection(connstrBuilder.toString()))

        testConn.open();

        if (testConnection.State == ConnectionState.Open) {

             Console.WriteLine("Connection successfully opened");

       可以把ConnectionString儲存在Web.config檔案中,然後在程式中使用WebConfigurationManager類進行讀取

<configuration>

    <add connectionString="Data Source=.;Initial Catalog=DawnEnterpriseDB;User ID=sa;Password=******" name="DawnEnterpriseDBConnectionString" providerName="System.Data.SqlClient" />

</configuration>

       如何讀取其中連接配接字元串的話在例1中有示例

    2.2 IDbConnection的共通行為與屬性

         因為相關的SqlConnection,OracleConnection,OleDBConnection與ODBCConnection都要實作IDBConnection接口,該接口規定了Connection類必須實作的一些行為和屬性

         2.2.1: 相關方法

             ● BeginTransaction() : 開始資料庫事務。

             ● ChangeDatabase(string database) : 更改目前資料庫。

             ● Open() : 打開一個資料庫連接配接,其設定由提供程式特定的 Connection 對象的 ConnectionString 屬性指定

             ● Close() : 關閉資料庫連接配接

             ● Dispose() : 法關閉或釋放由實作此接口的類的執行個體保持的檔案、流和句柄等非托管資源。

             ● CreateCommand(): 建立并傳回一個與該連接配接相關聯的 Command 對象。

         2.2.2: 相關屬性

             ● 包括ConnectionString、ConnectionTimeout、Database、Sate屬性

             以上,state屬性傳回的是一個ConnectionState枚舉對象,其中比較常用的的狀态值ConnectionState.Closed與ConnectionState.Open

    2.3 SqlConnection的一些其它特性

         2.3.1 使用RetrieveStatistics()方法獲得資料指令執行時的統計資訊,例如,可以擷取總指令執行時間的統計資訊。

                 統計資訊有以下常用屬性可以獲得:

                  ●   BytesReceived : 查詢中接收到的位元組數

                  ●   BytesSend : 發送出資料的位元組數

                  ●   ConnectionTime : 目前連接配接被開啟的總時間

                  ●   ExecutionTime : 傳回以毫秒為機關的連接配接執行時間

                  ●   IduCount: 用于傳回被執行Insert、Update、Delete指令的次數

                  ●   IduRows : 用于傳回被執行Insert、Update、Delete指令的行數

                  ●   SelectCount: 用于傳回Select指令執行的次數

                  ●   SelectRows : 用于傳回Select指令執行的行數

                  ●   …

例3: 取得資料庫查詢的執行時間      

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

// Movies類中的GetAll方法傳回一個List對象,該對象可以被GridView等控件做為資料源綁定

    public class Movies

        public List<Movies> GetAll(out long executeTime)  // executeTime作為out參數

            SqlCommand comm = new SqlCommand("WAITFOR DELAY '0:0:03';select Title,Director from Movies", conn);

            conn.StatisticsEnabled = true;   // 開啟擷取統計資訊的功能

                IDictionary stats = conn.RetrieveStatistics();

                executeTime = (long)stats["ExecutionTime"];

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

<script runat=”server”>

protected void ObjectDataSource1_Selected(object sender, ObjectDataSourceStatusEventArgs e)

    Label1.Text = e.OutputParameters["executeTime"].ToString();  // 取得傳回參數值

</script>

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" DataSourceID="ObjectDataSource1">

<asp:ObjectDataSource ID="ObjectDataSource1" TypeName="DawnDataObject.Movies" 

    SelectMethod="GetAll" runat="server" onselected="ObjectDataSource1_Selected">

    <SelectParameters>

        <asp:Parameter Name="executeTime" DbType="Int64" Direction="Output" /> <!-- 獲得GetAll的傳回參數 -->

    </SelectParameters>

</asp:ObjectDataSource>

<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>

         2.3.2 使用連接配接池

             資料庫連接配接是非常昂貴的資源,如果希望ASP.NET應用程式處理大量使用者請求的能力,使用連接配接池将會獲得更好的效率

             因為打開資料庫是一件很耗時的操作,每次使用資料庫時去建立連接配接效率将會很低,更好的辦法是建立一個緩存池存放被重複使用的資料庫連接配接。

             當使用SqlConnection時,連接配接時是預設開啟的,可以在連接配接字元串中使用Pooling=false将連接配接池關閉。

             關于連接配接池,必須注意二件事情:1.利用連接配接池時,調用SqlConnection.Close()方法關閉連接配接仍然非常重要。不顯示關閉,目前正在使用的連接配接就不會被放入連接配接池中。2.系統會跟據連接配接字元串的不同(使用字元串逐字比較方法),分别建立不同的連接配接池。是以,将連接配接字元串存放在站點配置檔案中,盡量不要在元件代碼中寫死連接配接字元串。

             ●  清空連接配接池

                ClearAllPools() : 用于清空系統中所有連接配接池中的資料庫連接配接

                ClearPool() : 清空第統中指定連接配接池裡的資料庫連接配接

             ● 設定連接配接字元串中連接配接池的屬性 [以上這些屬性的鍵/值對是在ConnectionString中指定的]

                Connection Timeout : 用于指定為秒為機關的連接配接生存最大值(預設為0,永不失效)

                Connection Reset : 是否自動 重置來自連接配接池中的連接配接(預設為true)

                Max Pool Size : 儲存在連接配接池中的最大連接配接數(預設為100)

                Min Pool Size : 儲存在連接配接池中的最小連接配接數

                Pooling : 是否開始連接配接池

    2.4 關閉連接配接 Close()與Dispose()

         以上兩個函數都可以關閉連接配接,但是它們有什麼不同的。以下摘錄的就是它們不同的地方:

• Calling Close on a connection object enables the underlying connection to be pooled.

• Calling Dispose on a connection object alleviates the need for you to call Close on it explicitly. It not only ensures that

the underlying connection can be pooled, but it also makes sure that allocated resources can now be garbage collected.

• Not calling either Close or Dispose will effectively kill your application performance by increasing the connection pool to a maximum limit,

and then everyone will have to wait for the next available connection object. Not only that, but even when the open connections fall out of scope,

they won’t be garbage collected for a relatively long time because the connection object itself doesn’t occupy that much memory—and the lack of memory

is the sole criterion for the garbage collector to kick in and do its work.

  In short, Dispose is the best option as it helps garbage collection and connection pooling, Close is second best option as it helps only connection pooling,

and not calling either Close or Dispose is so bad that you shouldn’t even go there.

    Command對象表示一個可以對資料源執行的指令。在這裡主要介紹的是SqlCommand對象,SqlCommand繼承自Command對象的公共基類DBCommand。

    3.1 SQL或存儲過程 指令的執行

       可以通過SqlCommand.ExecuteNonQuery方法來執行一個SQL指令,該方法不會傳回任何一個結果集。這個方法通常用來執行SQL語句中的Update、Insert、Delete指令。

       當然也可以用來執行如Create Table,Drop DataBase指令等

例4: 使用SqlCommand更新和删除電影記錄的方法UpdateMovie和DeleteMovie()

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

        private Int32 _id;

        public Int32 Id {

            get { return _id; }

            SqlCommand comm = new SqlCommand("select Id,Title,Director from Movies", conn);

            conn.StatisticsEnabled = true;

                    newmovie._id = (Int32)reader["Id"];

        // 對Movies表進行更新的方法

        public void UpdateMovie(int id,string title,string director)

            SqlCommand command = conn.CreateCommand();  // 使用SqlConnection.CreateCommand獲得SqlCommand對象

            command.CommandText = "Update Movies set Title=@title,Director=@director where Id=@id";

            command.Parameters.AddWithValue("@id", id);

            command.Parameters.AddWithValue("@title", title);

            command.Parameters.AddWithValue("@director", director);

            using(conn){

                command.ExecuteNonQuery();

        // 對Movies表進行删除的方法

        public void DeleteMovie(int id)

            // 使用new SqlCommand獲得SqlCommand對象

            SqlCommand command = new SqlCommand("delete from Movies where Id=@id",conn);

            using(conn)

            {

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

<asp:GridView ID="GridView1" runat="server" DataKeyNames="Id"

    AutoGenerateColumns="False" DataSourceID="ObjectDataSource1"

            onrowcommand="GridView1_RowCommand" onrowdeleting="GridView1_RowDeleting"

            AllowPaging="True" >

<Columns>

    <asp:BoundField HeaderText="Id" DataField="Id" Visible="false" />

    <asp:BoundField HeaderText="Title" DataField="Title" />

    <asp:BoundField HeaderText="Director" DataField="Director" />

    <asp:CommandField ShowEditButton="True" />

    <asp:CommandField ShowDeleteButton="True" />

</Columns>

</asp:GridView>

<asp:ObjectDataSource ID="ObjectDataSource1" TypeName="DawnDataObject.Movies"

    SelectMethod="GetAll" UpdateMethod="UpdateMovie" DeleteMethod="DeleteMovie" runat="server" onselected="ObjectDataSource1_Selected">

        <asp:Parameter Name="executeTime" DbType="Int64" Direction="Output" />

    <UpdateParameters>

        <asp:Parameter Name="Id" DbType="Int32" />

        <asp:Parameter Name="Title" DbType="String" />

        <asp:Parameter Name="Director" DbType="String" />

    </UpdateParameters>

    <DeleteParameters>

    </DeleteParameters>

    3.2 執行帶參數的指令

        大多數SQL指令都帶有參數,比如在執行對資料庫記錄更新時,就要提供參數表示資料記錄項的新值

        最好不要通過手工串接+=操作來建構SQL指令參數,因為這樣很容易遭受SQL注入攻擊。

        而使用SqlParameter對象來表示參數有很多種建構方式,最簡單的就像下面一樣來調用 SqlCommand.AddWithValue()方法

SqlCommand cmd = new SqlCommand("Insert Title(Title) values(@title)",conn);  // 注意,@title就算為字元串類型也不需要用''括起來

cmd.Parameters.AddWithValue("@title",”ASP.NET 2.0");

           當使用AddWithValue()方法時,SqlCommand自動識别并推測參數的類型和大小。該方法會假設字元串值類型為NVarChar, 整數值類型為Int,十進行數值類型為Decimal,以此類推。

           另一種建構參數的方法是直接建立SqlParameter對象,并加入到SqlCommand對象中。這樣做的好處是:可以顯式指定參數名稱,大小,精度,刻度和傳遞方向。

SqlCommand cmd = new SqlCommand("Insert Title(Title) values(@title)",conn);

SqlParameter paramTitle = new SqlParameter();

paramTitle.ParameterName = "@Title";

paramTitle.SqlDbType = SqlDbType.NVarChar;

paramTitle.Size = 50;

paramTitle.Value = "ASP.NET";

cmd.Parameters.Add(paramTitle);

           第三種方法,直接使用Add的一個重載方法來建立新的SqlParameter對象

cmd.Parameters.Add("@Title",SqlDbType.NVarChar,50).Value = "ASP.NET";

           以上,使用第一種方法比較簡便,直覺。

圖2: Command與Parameters的關系圖如下所示:

asp.net學習之ado.net(連接配接模式通路)

    3.3 執行存儲過程

        SqlCommand對象可以用來執行存儲過程 ,執行存儲過程如下所示:

SqlCommand cmd = new SqlCommand("GetTitles",conn);

cmd.CommandType = CommandType.StoredProcedure;

        在SqlCommand的第一個參數中,不要把參數放到裡面去,隻要放存儲過程名就行了,參數在SqlCommand的SqlParameters對象中添加

例5: 使用存儲過程而非SQL語句更新電影資訊記錄

=== 存儲過程建立 ===

create procedure UpdateMovie

(

    @id int,

    @title varchar(255),

    @director varchar(255)

)

as

    update movies set title=@title,director=@director where id=@id

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

// 隻要變更例4中的UpdateMovie函數,其它代碼不變

public void UpdateMovie(int id,string title,string director)

    SqlConnection conn = new SqlConnection(_connectionString);

    SqlCommand command = conn.CreateCommand();  // 使用SqlConnection.CreateCommand獲得SqlCommand對象

    // 與例4相比,隻要變更下面兩句

    command.CommandText = "UpdateMovie";   

    command.CommandType = CommandType.StoredProcedure;

    command.Parameters.AddWithValue("@id", id);

    command.Parameters.AddWithValue("@title", title);

    command.Parameters.AddWithValue("@director", director);

    using(conn){

        conn.Open();

        command.ExecuteNonQuery();

        存儲過程可以有傳回值(returnvalue),也可以有輸出參數(output),那麼,作為程式,如何調用存儲過程後,取得相應的傳回值呢。

例6: 從存儲過程中取得傳回值

=== SelectMovies存儲過程 ===

CREATE PROCEDURE dbo.GetMovieCount

AS

RETURN (SELECT COUNT(*) FROM Movies)

=== movies.aspx ===

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

<script runat="server">

void Page_Load()

    lblMovieCount.Text = GetMovieCount().ToString();

private int GetMovieCount()

    int result = 0;

    string connectionString = WebConfigurationManager.connectionString["Movies"].ConnectionString;

    SqlConnection con = new SqlConnection(connectionString);

    SqlCommand cmd = new SqlCommand("GetMovieCount", con);

    cmd.CommandType = CommandType.StoredProcedure;

    cmd.Parameters.Add("@ReturnVal", SqlDbType.Int).Direction =ParameterDirection.ReturnValue; // 設定傳回值參數

    using (con)

        con.Open();

        cmd.ExecuteNonQuery();  // 好像一定要使用ExecuteNonQuery,如果使用ExecuteReader,則相應的傳回值就取不出來。

        result = (int)cmd.Parameters["@ReturnVal"].Value;  // 取得傳回值參數值

    return result;

例7: 從存儲過程中取得OUTPUT值

CREATE PROCEDURE dbo.GetBoxOfficeTotals

    @SumBoxOfficeTotals Money OUTPUT

SELECT @SumBoxOfficeTotals = SUM(BoxOfficeTotals) FROM Movies

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

<script runat=server>

public List<Movie5> GetBoxOffice(out decimal SumBoxOfficeTotals)

    List<Movie5> results = new List<Movie5>();

    SqlConnection con = new SqlConnection(_connectionString);

    SqlCommand cmd = new SqlCommand("GetBoxOfficeTotals", con);

    cmd.Parameters.Add("@SumBoxOfficeTotals", SqlDbType.Money).Direction = ParameterDirection.Output;

        SqlDataReader reader = cmd.ExecuteReader();  // 使用OUTPUT參數,可以使用ExecuteReader。與ReturnValue不同。

        while (reader.Read())

            Movie5 newMovie = new Movie5();

            newMovie.Title = (string)reader["Title"];

            newMovie.BoxOfficeTotals = (decimal)reader["BoxOfficeTotals"];

            results.Add(newMovie);

    reader.Close();

    SumBoxOfficeTotals = (decimal)cmd.Parameters["@SumBoxOfficeTotals"].

    Value;

    return results;

    3.4 單一的傳回值

       如果需要從資料庫查詢中擷取單一的傳回值,可以使用SqlCommand.ExecuteScalar()方法。該方法總是傳回查詢結果集中第一行第一列的資料值。

       ExecuteScalar方法傳回值的類型為object,可以将它轉換為想要的類型。

    3.5 傳回結果集

       在例1、例3、例4中,利用了SqlCommand.ExecuteReader()方法,調用這個方法将傳回一個SqlDataReader對象,我們使用該對象讀取每一行資料,并将資料存入一個泛型集合(List<Movie>)中,

       如果希望省略複制步驟,并且不把擷取的記錄存入集合對象中,那麼這裡需要向ExecuteReader方法傳遞一個CommandBehavior.CloseConnection參數,該參數會使資料庫連接配接與SqlDataReader對象關聯起來,當從SqlDataReader對象中讀取了所有的資料記錄後。連接配接将自動關閉。

       預設的向ExecuteReader方法傳遞一個CommandBehavior.Default參數,它表示此查詢可能傳回多個結果集。執行查詢可能會影響資料庫狀态。調用SqlCommand.ExecuteReader(CommandBehavior.Default)就相當于調用SqlCommand.ExecuteReader()

例8: 不使用泛型集合作資料源

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

        public SqlDataReader GetDataReader()

            SqlCommand command = new SqlCommand("SelectMovies", conn);

            command.CommandType = CommandType.StoredProcedure;

            conn.Open();

            return command.ExecuteReader(CommandBehavior.CloseConnection);  // 直接傳回DataReader作為資料源

        public void UpdateMovies() {…}

        public void DeleteMovies() {…}

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

<!-- 因為DataReader的原因,這裡的GridView不支援分頁,排序 -->

            AutoGenerateColumns="False" DataSourceID="ObjectDataSource1"

            onrowcommand="GridView1_RowCommand" onrowdeleting="GridView1_RowDeleting" >

    SelectMethod="GetDataReader" UpdateMethod="UpdateMovie" DeleteMethod="DeleteMovie" runat="server" >

</asp:ObjectDataSource>  

    DataReader對象可以用來表示資料庫查詢的結果。該對象可以通過調用Command對象的ExecuteReader()方法獲得.

    調用DataReader的HasRows屬性或者Read()方法,可以判斷DataReader對象所表示的查詢結果中是否包含資料行記錄

    調用Reader()方法,可以将DataReader對象所表示的目前資料行向前移動一行,移動一行後,傳回true,到末尾,無法向前移動,傳回false.

    任意時刻上,DataReader對象隻表示查詢結果集中的某一行記錄。 

圖3:DataReader與Command關系如下圖所示:

asp.net學習之ado.net(連接配接模式通路)

    4.1 獲得DataReader對象中資料行的字段值

         如果要獲得目前行中相應的字段值,可以使用以下方法來獲得:

         ● string title = (string)reader["title"];     // 通過字段名稱傳回Object類型,再轉換

         ● string title = (string)reader[0];           // 通過字段位置傳回Object類型,再轉換

         ● string title = reader.GetString(0);       // 通過字段位置傳回string類型。

         ● string title = reader.GetSqlString(0);   // 通過字段位置,傳回SqlString類型。

     4.2 傳回多個結果集

         一個簡單的資料庫查詢可以傳回多個結果集,如以下SQL語句

         "select * from MovieCategories; select * from movies"

         在一次指令送出中執行多個查詢可以提高效率,也可以避免戰勝多個資料庫連接配接。

         在傳回多個結果集的情況下,可以使用SqlDataReader的MoveResult()方法切換到下一個結果集中。

例9:傳回多個結果集

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

namespace mulitResults

    public class DataLayer1

        private static readonly string _connectionString;

        public class MovieCategory  // 表示電影種類實體,注意是嵌套類

            private int _id;

            private string _name;

            public int Id

                get { return _id; }

                set { _id = value; }

            public string Name

                get { return _name; }

                set { _name = value; }

        public class Movie  // 表示電影實體,注意是嵌套類

            private string _title;

            private int _categoryId;

            public string Title

                get { return _title; }

                set { _title = value; }

            public int CategoryId

                get { return _categoryId; }

                set { _categoryId = value; }

        // 不像剛才實體清單作為傳回值反回,現在作為參數傳回

        public static void GetMovieData(List<DataLayer1.MovieCategory> movieCategories,List<DataLayer1.Movie> movies)

            string commandText = "SELECT Id,Name FROM MovieCategories;SELECT Title,CategoryId FROM Movies";

            SqlConnection con = new SqlConnection(_connectionString);

            SqlCommand cmd = new SqlCommand(commandText, con);

            using (con)

                // Execute command

                con.Open();

                SqlDataReader reader = cmd.ExecuteReader();

                // Create movie categories

                while (reader.Read())

                {

                    DataLayer1.MovieCategory newCategory = new DataLayer1.

                    MovieCategory();

                    newCategory.Id = (int)reader["Id"];

                    newCategory.Name = (string)reader["Name"];

                    movieCategories.Add(newCategory);

                // Move to next result set

                reader.NextResult();

                // Create movies

                    DataLayer1.Movie newMovie = new DataLayer1.Movie();

                    newMovie.Title = (string)reader["Title"];

                    newMovie.CategoryId = (int)reader["CategoryID"];

                    movies.Add(newMovie);

        static DataLayer1()

            _connectionString = WebConfigurationManager.ConnectionStrings["Movies"].ConnectionString;

=== ShowMovies.aspx ===

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

    // Get database data

    List<DataLayer1.MovieCategory> categories = new List<DataLayer1.MovieCategory>();

    List<DataLayer1.Movie> movies = new List<DataLayer1.Movie>();

    DataLayer1.GetMovieData(categories, movies);

    // Bind the data

    grdCategories.DataSource = categories;

    grdCategories.DataBind();

    grdMovies.DataSource = movies;

    grdMovies.DataBind();

<h1>Movie Categories</h1>

<asp:GridView id="grdCategories" Runat="server" />

<h1>Movies</h1>

<asp:GridView id="grdMovies" Runat="server" />

    4.3 多活動結果集MARS (Multiple Active Resultsets)

        ADO.NET 2.0提供了MARS的新特性,在以前版本的ADO.NET中,資料庫連接配接在一個有限時間段内能且隻能表示一個查詢結果集。

        利用MARS特性,可以使用單一的資料庫連接配接表示多個查詢結果集。

        MARS在以下場景中很有價值:程式對一個結果集周遊的過程中,同時需要對目前結果集中的記錄執行一些額外的資料庫操作。

        打開MARS功能,需要在連接配接字元口串中包含以下字段: MultipleActiveResultSets=True;

例10: 使用多個結果集

asp.net學習之ado.net(連接配接模式通路)
asp.net學習之ado.net(連接配接模式通路)

void BuildTree()

    // Create MARS connection

    // Create Movie Categories command

    string cmdCategoriesText = "SELECT Id,Name FROM MovieCategories";

    SqlCommand cmdCategories = new SqlCommand(cmdCategoriesText, con);

    // Create Movie command

    string cmdMoviesText = "SELECT Title FROM Movies " + "WHERE CategoryId=@CategoryID";

    SqlCommand cmdMovies = new SqlCommand(cmdMoviesText, con);

    cmdMovies.Parameters.Add("@CategoryId", SqlDbType.Int);

        // 打開一個結果集,表示電影目錄

        SqlDataReader categories = cmdCategories.ExecuteReader();

        while (categories.Read())

            // Add category node

            int id = categories.GetInt32(0);

            string name = categories.GetString(1);

            TreeNode catNode = new TreeNode(name);

            TreeView1.Nodes.Add(catNode);

            // Iterate through matching movies

            cmdMovies.Parameters["@CategoryId"].Value = id;

            SqlDataReader movies = cmdMovies.ExecuteReader();  // 打開另一個結果集.注:上一個結果集還沒有被關閉.

            while (movies.Read())

                // Add movie node

                string title = movies.GetString(0);

                TreeNode movieNode = new TreeNode(title);

                catNode.ChildNodes.Add(movieNode);

            movies.Close();

    if (!Page.IsPostBack)

        BuildTree();

<asp:TreeView id=”TreeView1” Runat=”server” />