程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> c# 數據庫編程(利用DataSet 和 DataAdaper對象操作數據庫--單表操作)

c# 數據庫編程(利用DataSet 和 DataAdaper對象操作數據庫--單表操作)

編輯:C#基礎知識

一、概述

前面2篇文章,介紹了使用SqlCommand對象利用sql命令來操作數據庫。

這篇文章我們來介紹使用c#的DataSet 和 DataAdaper對象操作操作數據庫。

先來介紹下這兩個對象是干啥的。

1、DataSet對象

顧名思義,DataSet 可叫做數據集,可以簡單的理解為一個臨時數據庫,其中可包含多個表(DataTable),表中有記錄。

DataSet將從數據源(如數據庫)中獲得的數據保存在內存中,應用程序與內存中的DataSet進行交互,在這期間,不需要連接數據庫。

也就是說,一旦DataSet獲取數據後,就可以把數據庫鏈接關閉掉,這可以節約資源,提高數據的訪問和處理速度(因為是在內存中操作)。

當然,也是因為DataSet是在內存中,可以理解成一個緩存,數據放的越多,占系統內存越多,這個也是需要考慮的。

應用程序除了可以從DataSet中獲取數據,還可以更新DataSet中的數據,後面可以使用DataAdaper對象同步到數據源中,避免了額外的寫代碼處理,提高了代碼編寫的效率和質量。

2、DataAdaper對象

DataAdaper,可稱為數據適配器,它就是負責把DataSet和真實的數據源連接起來。本身DataSet對象是不直接和數據源打交道的,它只是個緩存,用戶存儲數據。

DataAdaper的工作機制是,它利用Connection對象連接數據庫,使用相關的Command對象封裝的命令(如sql語句)獲取數據,並把得到的數據填充到DataSet對象中。後續DataSet對象中的數據更新後需要同步到數據源中,也是由DataAdaper對象使用相關的Command對象來負責同步數據。

下面我們通過例子來說明如何使用。

 操作的表 userinfo有兩個字段 username 和 password,其中username為主鍵。

二、查詢數據舉例

直接上例子代碼:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;

namespace DbExample
{
    class DataSetExample
    {
        public void fetchData()
        {
            DataSet dataSet = new DataSet();
            SqlDataAdapter adapter = new SqlDataAdapter();
            SqlConnection conn = getConnection(); 
            try
            {
                conn.Open();
                SqlCommand command = new SqlCommand("select * from userinfo", conn); //綁定的sql命令
                adapter.SelectCommand = command;
                adapter.Fill(dataSet, "userinfo"); //將數據獲取後裝載到dataSet中,當作一張表存儲在內存中                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "查詢數據失敗");
            }
            finally
            {
                conn.Close();
            }
            showTable(dataSet);
        }

        private void showTable(DataSet dataSet)
        {
            DataTable table = dataSet.Tables["userinfo"]; //也可以通過序號獲取
            int num = table.Rows.Count;
            MessageBox.Show(num.ToString()); //獲取表的記錄數
            for (int i = 0; i < num; i++)
            {
                string re = table.Rows[i][0].ToString() + "," + table.Rows[i][1].ToString();
                MessageBox.Show(re);
            }
            // 或者下面的方式遍歷更好
            foreach (DataRow row in table.Rows)
            {
                string re = row[0].ToString() + "," + row[1].ToString();
                MessageBox.Show(re);
            }
            //或者
            DataRow[] rows = table.Select(); //可以通過參數控制輸出的內容,還可以排序
            foreach (DataRow row in table.Rows)
            {
                string re = row[0].ToString() + "," + row[1].ToString();
                MessageBox.Show(re);
            }
        }


        private SqlConnection getConnection()
        {
            string strConnection = @"Data Source = localhost\SQLEXPRESS; Initial Catalog = mydb; User Id = sa; Password = 12345678;";
            SqlConnection conn = new SqlConnection(strConnection);
            return conn;
        }
    }
}

從上面代碼中可以看出, showTable方法是在conn關閉後執行的,說明了一旦數據到了dataset中,就在內存中了,與數據庫是否保持連接無關了。
也可以看出,DataAdaper對象是利用綁定的command對象來實際獲取數據的,並利用自己的Fill方法將數據放到dataset對象中。

 

三、同步更新數據舉例(自動生成更新命令)

上面我們舉了個查詢的數據,沒有對dataset數據進行修改。下面例子會對dataset數據進行修改,然後同步到數據庫中。

 我們先給出一個例子代碼:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;

namespace DbExample
{
    class DataSetExample
    {
        public void fetchData()
        {
            DataSet dataSet = new DataSet();
            SqlDataAdapter adapter = new SqlDataAdapter();
            SqlConnection conn = getConnection(); 
            try
            {
                conn.Open();
                SqlCommand command = new SqlCommand("select * from userinfo", conn); //綁定的sql命令
                adapter.SelectCommand = command;
                SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
                adapter.Fill(dataSet, "userinfo"); //將數據獲取後裝載到dataSet中,當作一張表存儲在內存中                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "操作失敗");
            }
            finally
            {
                conn.Close();
            }
            deleteRow(dataSet, adapter);
            MessageBox.Show("操作成功");
        }

        private void deleteRow(DataSet dataSet, SqlDataAdapter adapter)
        {
            DataTable table = dataSet.Tables["userinfo"];
            table.Rows[2].Delete(); //刪除第2條
            adapter.Update(dataSet, "userinfo"); //同步到數據庫
        }

        private SqlConnection getConnection()
        {
            string strConnection = @"Data Source = localhost\SQLEXPRESS; Initial Catalog = mydb; User Id = sa; Password = Xqh980234;";
            SqlConnection conn = new SqlConnection(strConnection);
            return conn;
        }
    }
}

與前面第一個查詢數據的例子相比,我們在fetchData方法的try代碼塊中增加了一行代碼
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);

在fetchData方法的結尾將調用showTable 方法 改為 調用deleteRow方法。

執行上面代碼,我們會發現userinfo表中的第3條記錄被刪除了,但是代碼中沒看到任何顯示的 delete sql語句的執行。

下面我們來解釋下背後的原因。

 在文章的開頭我們提到,DataSet對象只是個內存緩存,它是通過DataAapter對象來操作數據庫的,而DataAapter對象是通過其關聯的Command對象來具體實現數據庫操作的。

我們看到的代碼中的如下語句:

SqlCommand command = new SqlCommand("select * from userinfo", conn); //綁定的sql命令
adapter.SelectCommand = command;

這個DataAapter對象綁定了 SelectCommand 對象,這個Command通過其指定的查詢sql獲取數據後放到DataSet對象中。

對於查詢命令,還有一種更簡單的方式,用一個語句將上面兩條語句合一,如下:

adapter = new SqlDataAdapter("select * from userinfo", conn);

除了查詢外,還有DeleteCommand、InsertCommand、UpdateCommand 來完成更新操作。

但是在特定條件下,這三個Command不需要顯示的指定,只需要加上下面語句。

SqlCommandBuilder builder = new SqlCommandBuilder(adapter);

加上這個語句後,就會自動構建三個Command對象。

這就是為什麼上面的代碼沒看到有DeleteCommand對象,卻可以通過DataAapter來實現數據庫記錄的刪除操作。

需要說明的是,自動生成更新Command對象,需要滿足的條件是:

必須要綁定SelectCommand 對象,且指定的select語句只能包含單張表的操作,還必須返回至少一個主鍵或唯一列。

還需要注意的是:

要想同步數據庫,完成記錄的刪除,不能調用 table.Rows.Remove 或 Clear方法 ,這些方法會刪除DataSet中的數據,但DataAapter不是以這個為依據來判斷是否要刪除記錄,而是要調用DataRow對象的Delete方法,如上面的代碼:

table.Rows[2].Delete();

需要說明的是,調用了上面的Delete方法,在同步到數據庫之前,這條記錄在DataSet中還存在,但是卻不能訪問它,訪問會報錯。

但是在同步之後,該記錄將會從DataSet中被刪除。

而且要注意的是,在同步前,不能調用rows的Remove方法把該記錄從DataSet中刪除,這樣的話,同步時,記錄將不會從數據中刪除。

上面講的幾個注意點比較繞,需要弄清楚,並且寫代碼時要注意,否則很容易會導致數據紊亂,與預期的不一致。

上面我們看了刪除記錄的操作,下面我們看下增加記錄。

增加記錄比較簡單,沒有特別的注意點,代碼如下:

DataTable table = dataSet.Tables["userinfo"];
table.Rows.Add(new string[] { "x1","p1"});
table.Rows.Add(new string[] { "x2", "p2" });
adapter.Update(dataSet, "userinfo"); //同步到數據庫

上面代碼先往dataSet中插入2條記錄,再同步到數據庫。注意,無論是同步前,還是同步後,都能從dataSet中訪問到這兩條記錄。

我們再看如何修改記錄同步到數據庫。

DataTable table = dataSet.Tables["userinfo"];
table.Rows[2][0] = "x21";
table.Rows[2][1] = "kkk";
adapter.Update(dataSet, "userinfo"); //同步到數據庫

上面代碼修改dataSet中的第3條記錄的兩個字段,再同步到數據庫。注意,無論是同步前,還是同步後,都能從dataSet中訪問到這兩條記錄。

 

四、同步更新數據(非自動)

上面介紹了如何將修改後的DataSet數據同步到數據庫中,並且更新命令是自動生成的,下面介紹如何手工設置。

我們先看一個update的例子。

public void fetchDataEx()
        {
            DataSet dataSet = new DataSet();
            SqlDataAdapter adapter = null;
            SqlConnection conn = getConnection();
            try
            {
                conn.Open();
                adapter = new SqlDataAdapter("select username,password from userinfo", conn);
                adapter.UpdateCommand = new SqlCommand(
                    "update userinfo set password=@password " +
                    "where username =@username", conn);
                adapter.UpdateCommand.Parameters.Add("@password", SqlDbType.VarChar, 50, "password");
                adapter.UpdateCommand.Parameters.Add("@username", SqlDbType.VarChar, 50, "username");
                adapter.Fill(dataSet, "userinfo");                 
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "操作失敗");
            }
            finally
            {
                conn.Close();
            }
            deleteRow(dataSet, adapter);
            MessageBox.Show("操作成功");
        }

        private void deleteRow(DataSet dataSet, SqlDataAdapter adapter)
        {
            DataTable table = dataSet.Tables["userinfo"];
            table.Rows[2][1] = "y26";
            adapter.Update(dataSet, "userinfo");        }

上面代碼,adapter顯示的綁定了一個UpdateCommand對象,其中包含了一個update語句。
需要注意的是,上面的update語句沒有更新主鍵username,如果要更新主鍵,則需要采用如下的寫法。

adapter.UpdateCommand = new SqlCommand(
                    "update userinfo set username =@newusername,password=@password " +
                    "where username =@username", conn);                
                adapter.UpdateCommand.Parameters.Add("@password", SqlDbType.VarChar, 50, "password");
                adapter.UpdateCommand.Parameters.Add("@newusername", SqlDbType.VarChar, 50, "username");
                SqlParameter parameter = adapter.UpdateCommand.Parameters.Add("@username", SqlDbType.VarChar, 50, "username");
                parameter.SourceVersion = DataRowVersion.Original;


//更新DataSet的代碼
DataTable table = dataSet.Tables["userinfo"];
table.Rows[2][0] = "good2";
table.Rows[2][1] = "xxx12";
adapter.Update(dataSet, "userinfo"); //同步到數據庫

上面代碼可以看出,利用 parameter.SourceVersion = DataRowVersion.Original 將update語句中的where條件的username字段的取值設置為取原始值。

插入和刪除代碼的命令設置如下

adapter.DeleteCommand = new SqlCommand( "delete from userinfo where username =@username", conn);
adapter.DeleteCommand.Parameters.Add("@username", SqlDbType.VarChar, 50, "username");

adapter.InsertCommand = new SqlCommand("insert into userinfo values(@username,@password)", conn);
 adapter.InsertCommand.Parameters.Add("@username", SqlDbType.VarChar, 50, "username");
adapter.InsertCommand.Parameters.Add("@password", SqlDbType.VarChar, 50, "password");

可以看出,如果是單表操作,最好還是采用上個例子講的自動生成更新command的方式,人工設置的方式還是比較麻煩的。

還有需要注意的時候,有時對DataSet做了多次操作,會導致對更新數據庫的順序(也就是說對執行 update ,delete,insert的順序)有要求。

這時需要顯示的指明同步的順序。這時可以使用 DataTable 的 Select 方法來返回僅引用具有特定 RowState 的 DataRow 數組。然後可以將返回的 DataRow 數組傳遞到 DataAdapter 的 Update 方法來處理已修改的行。通過指定要更新的行的子集,可以控制處理插入、更新和刪除的順序。如:

DataTable table = dataSet.Tables["userinfo"];
// First process deletes.
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));
// Next process updates.
adapter.Update(table.Select(null, null, DataViewRowState.ModifiedCurrent));
// Finally, process inserts.
adapter.Update(table.Select(null, null, DataViewRowState.Added));

本文介紹了,如何利用DataSet 和 DataAdaper對象來操作數據庫。這裡介紹的是單表操作。對於跨表的操作,會更為復雜,這在後面的文章中介紹。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved