asp.net学习之ado.net(连接模式访问)
?? ado.net框架支持兩種模式的數據訪問: 連接模式(Connected)和非連接模式(disconnected)。這一節介紹如何使用連接模式訪問數據庫中的數據,利用ADO.NET中的Connection,Command,DataReader來獲取和修改數據庫中的數據
1. 連接模式的數據訪問
???? 連接模式要使用到的三個核心類:
???? ● 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的關系圖如下所示:
例1: 一個簡單的連接數據庫查詢的例子
=== App_Code\DawnDataObject.cs ===
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:ObjectDataSource ID="ObjectDataSource1" TypeName="DawnDataObject.Movies" SelectMethod="GetAll" runat="server"?/>
2. 使用Connection對象
?? Connection對象表示數據源的連接,實例化Connection對象時,需要向構造函數傳遞一個連接字符串。連接字符串包含了連接到數據源所需要的位置和安全認證信息
?? Connection對象也提供了相應的方法對數據庫進行打開和關閉操作;提供了相應的屬性確認數據庫的狀態。
?? 2.1 連接字符串
??????? 一個最普通的連接字符串如下所示:
??? SqlConnection conn =?new SqlConnection(_connectionSring);?? // 可以在建立SqlConnection對象時把連接字符串傳遞給構造參數
?????? 也可以使用Connection對象的ConnectionString屬性來獲取或設置用于打開 SQL Server 數據庫的字符串
??? conn.ConnectionString =?"Persist Security Info=False;Integrated Security=true;Initial Catalog=Northwind;server=(local)";
?????? ado.net提供了相應的DbConnectionStringBuilder類來管理數據庫連接字符串。相對應的,sqlClient命名空間中就包含了一個SqlConnectionStringBuilder類。
例2:使用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類進行讀取
??? <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: 取得數據庫查詢的執行時間??????
=== App_Code\DawnDataObject.cs ===
// Movies類中的GetAll方法返回一個List對象,該對象可以被GridView等控件做為數據源綁定
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(out?long executeTime)? // executeTime作為out參數
??????? {
??????????? List<Movies> result =?new List<Movies>();
??????????? SqlConnection conn =?new SqlConnection(_connectionString);
??????????? SqlCommand comm =?new SqlCommand("WAITFOR DELAY '0:0:03';select Title,Director from Movies", conn);
??????????? conn.StatisticsEnabled =?true;?? // 開啟獲取統計信息的功能
??????????? 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);
??????????????? }
??????????????? IDictionary stats = conn.RetrieveStatistics();
??????????????? executeTime = (long)stats["ExecutionTime"];
??????????????? return result;
??????????? }
??????? }
??? }
}
=== Movies.aspx ===
<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 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.
3. Command對象
??? Command對象表示一個可以對數據源執行的命令。在這里主要介紹的是SqlCommand對象,SqlCommand繼承自Command對象的公共基類DBCommand。
??? 3.1 SQL或存儲過程 命令的執行
?????? 可以通過SqlCommand.ExecuteNonQuery方法來執行一個SQL命令,該方法不會返回任何一個結果集。這個方法通常用來執行SQL語句中的Update、Insert、Delete命令。
?????? 當然也可以用來執行如Create Table,Drop DataBase命令等
例4: 使用SqlCommand更新和刪除電影記錄的方法UpdateMovie和DeleteMovie()
=== App_Code\DawnDataObject.cs ===
namespace? DawnDataObject
{
??? public?class Movies
??? {
??????? public?static?readonly?string _connectionString;? // 連接數據庫字符串為靜態成員,每個實例共享。
??????? static Movies(){
??????????? _connectionString = WebConfigurationManager.ConnectionStrings["DawnEnterpriseDBConnectionString"].
??????????????? ConnectionString;
??????? }
??????? private?string _title;
??????? private?string _director;
??????? private Int32 _id;
??????? // Movies類中包括的屬性有Title、Director
??????? public?string Title{
??????????? get { return _title; }
??????????? set { _title = value; }
??????? }
??????? public?string Director {
??????????? get { return _director; }
??????????? set { _director = value; }
??????? }
??????? public Int32 Id {
??????????? get { return _id; }
??????? }
??????? // Movies類中的GetAll方法返回一個List對象,該對象可以被GridView等控件做為數據源綁定
??????? public List<Movies> GetAll(out?long executeTime)? // executeTime作為out參數
??????? {
??????????? List<Movies> result =?new List<Movies>();
??????????? SqlConnection conn =?new SqlConnection(_connectionString);
??????????? SqlCommand comm =?new SqlCommand("select Id,Title,Director from Movies", conn);
??????????? conn.StatisticsEnabled =?true;
??????????? 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"];
??????????????????? newmovie._id = (Int32)reader["Id"];
??????????????????? result.Add(newmovie);
??????????????? }
??????????????? IDictionary stats = conn.RetrieveStatistics();
??????????????? executeTime = (long)stats["ExecutionTime"];
??????????????? return result;
??????????? }
??????? }
??????? // 對Movies表進行更新的方法
??????? public?void UpdateMovie(int id,string title,string director)
??????? {
??????????? SqlConnection conn =?new SqlConnection(_connectionString);
??????????? 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){
??????????????? conn.Open();
??????????????? command.ExecuteNonQuery();
??????????? }
??????? }
??????? // 對Movies表進行刪除的方法
??????? public?void DeleteMovie(int id)
??????? {
??????????? SqlConnection conn =?new SqlConnection(_connectionString);
??????????? // 使用new SqlCommand獲得SqlCommand對象
??????????? SqlCommand command =?new SqlCommand("delete from Movies where Id=@id",conn);
??????????? command.Parameters.AddWithValue("@id", id);
??????????? using(conn)
??????????? {
??????????????? conn.Open();
??????????????? command.ExecuteNonQuery();
??????????? }
??????? }
??? }
}
=== Movies.aspx ===
Code<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">
??? <SelectParameters>
??????? <asp:Parameter Name="executeTime" DbType="Int64" Direction="Output"?/>
??? </SelectParameters>
??? <UpdateParameters>
??????? <asp:Parameter Name="Id" DbType="Int32"?/>
??????? <asp:Parameter Name="Title" DbType="String"?/>
??????? <asp:Parameter Name="Director" DbType="String"?/>
??? </UpdateParameters>
??? <DeleteParameters>
??????? <asp:Parameter Name="Id" DbType="Int32"?/>
??? </DeleteParameters>
</asp:ObjectDataSource>
?
??? 3.2 執行帶參數的命令
??????? 大多數SQL命令都帶有參數,比如在執行對數據庫記錄更新時,就要提供參數表示數據記錄項的新值
??????? 最好不要通過手工串接+=操作來構建SQL命令參數,因為這樣很容易遭受SQL注入攻擊。
??????? 而使用SqlParameter對象來表示參數有很多種構建方式,最簡單的就像下面一樣來調用 SqlCommand.AddWithValue()方法
cmd.Parameters.AddWithValue("@title",”ASP.NET 2.0");
?????????? 當使用AddWithValue()方法時,SqlCommand自動識別并推測參數的類型和大小。該方法會假設字符串值類型為NVarChar, 整數值類型為Int,十進行數值類型為Decimal,以此類推。
?????????? 另一種構建參數的方法是直接創建SqlParameter對象,并加入到SqlCommand對象中。這樣做的好處是:可以顯式指定參數名稱,大小,精度,刻度和傳遞方向。
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的關系圖如下所示:
??
??? 3.3 執行存儲過程
??????? SqlCommand對象可以用來執行存儲過程 ,執行存儲過程如下所示:
SqlCommand cmd = new SqlCommand("GetTitles",conn);
cmd.CommandType = CommandType.StoredProcedure;
??????? 在SqlCommand的第一個參數中,不要把參數放到里面去,只要放存儲過程名就行了,參數在SqlCommand的SqlParameters對象中添加
例5: 使用存儲過程而非SQL語句更新電影信息記錄
=== 存儲過程創建 ===
(
??? @id?int,
??? @title?varchar(255),
??? @director?varchar(255)
)
as
??? update movies set title=@title,director=@director?where id=@id
=== App_Code\DawnDataObject.cs ===
// 只要變更例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存儲過程 ===
AS
RETURN (SELECT?COUNT(*) FROM Movies)
=== movies.aspx ===
<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;
}
</script> 例7: 從存儲過程中取得OUTPUT值
=== 存儲過程創建 ===
CREATE?PROCEDURE dbo.GetBoxOfficeTotals
(
??? @SumBoxOfficeTotals?Money OUTPUT
)
AS
SELECT?@SumBoxOfficeTotals?=?SUM(BoxOfficeTotals) FROM Movies
=== movies.aspx ===
<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.CommandType = CommandType.StoredProcedure;
??? cmd.Parameters.Add("@SumBoxOfficeTotals", SqlDbType.Money).Direction = ParameterDirection.Output;
??? using (con)
??? {
??????? con.Open();
??????? 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;
}
</script>
??? 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: 不使用泛型集合作數據源
=== App_Code\DawnDataObject.cs ===
namespace? DawnDataObject
{
??? public?class Movies
??? {
??????? public SqlDataReader GetDataReader()
??????? {
??????????? SqlConnection conn =?new SqlConnection(_connectionString);
??????????? SqlCommand command =?new SqlCommand("SelectMovies", conn);
??????????? command.CommandType = CommandType.StoredProcedure;
??????????? conn.Open();
??????????? return command.ExecuteReader(CommandBehavior.CloseConnection);? // 直接返回DataReader作為數據源
??????? }
??????
??????? public?void UpdateMovies() {…}
??????? public?void DeleteMovies() {…}
??? }
}
=== movies.aspx ===
<!-- 因為DataReader的原因,這里的GridView不支持分頁,排序 -->
<asp:GridView ID="GridView1" runat="server" DataKeyNames="Id"
??????????? AutoGenerateColumns="False" DataSourceID="ObjectDataSource1"
??????????? onrowcommand="GridView1_RowCommand" onrowdeleting="GridView1_RowDeleting"?>
<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:ObjectDataSource ID="ObjectDataSource1" TypeName="DawnDataObject.Movies"
??? SelectMethod="GetDataReader" UpdateMethod="UpdateMovie" DeleteMethod="DeleteMovie" runat="server"?>
??? <UpdateParameters>
??????? <asp:Parameter Name="Id" DbType="Int32"?/>
??????? <asp:Parameter Name="Title" DbType="String"?/>
??????? <asp:Parameter Name="Director" DbType="String"?/>
??? </UpdateParameters>
??? <DeleteParameters>
??????? <asp:Parameter Name="Id" DbType="Int32"?/>
??? </DeleteParameters>
</asp:ObjectDataSource>??
4. DataReader對象
??? DataReader對象可以用來表示數據庫查詢的結果。該對象可以通過調用Command對象的ExecuteReader()方法獲得.
??? 調用DataReader的HasRows屬性或者Read()方法,可以判斷DataReader對象所表示的查詢結果中是否包含數據行記錄
??? 調用Reader()方法,可以將DataReader對象所表示的當前數據行向前移動一行,移動一行后,返回true,到末尾,無法向前移動,返回false.
??? 任意時刻上,DataReader對象只表示查詢結果集中的某一行記錄。?
圖3:DataReader與Command關系如下圖所示:
??? 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:返回多個結果集
=== App_Code\DawnDataObject.cs ===
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
??????????????? while (reader.Read())
??????????????? {
??????????????????? 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 ===
<script runat="server">
void Page_Load()
{
??? // 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();
}
</script>
<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: 使用多個結果集
<script runat=”server”>
void BuildTree()
{
??? // Create MARS connection
??? SqlConnection con =?new SqlConnection(_connectionString);
??? // 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);
??? using (con)
??? {
??????? con.Open();
??????? // 打開一個結果集,表示電影目錄
??????? 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();
??? }
}
void Page_Load()
{
??? if (!Page.IsPostBack)
??????? BuildTree();
}
</script>
<asp:TreeView id=”TreeView1” Runat=”server” />
總結
以上是生活随笔為你收集整理的asp.net学习之ado.net(连接模式访问)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么让plsqldev恢复界面视图复位
- 下一篇: .Net程序员学用Oracle系列(18