程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 胡亂理解ADO.NET(四)

胡亂理解ADO.NET(四)

編輯:關於.NET

在上兩篇文章中,對於dataset做了個簡單的探討.很多次提到,可以把dataset看作是內存中的數據庫.既然是數據庫,那麼首要任務就是存儲數據用的.而之前,我所舉的的例子都是手工往dataset裡添加數據,其實這個並不是我們最想要的.我們最想要的是能用程序把數據庫裡的數據讀取出來然後裝到dataset裡,然後用程序來處理dataset裡的數據.當處理好dataset裡的數據後,我們還想把這些數據再更新到數據庫中. 這樣就能與數據庫斷開連接而處理數據了(把數據庫中的數據讀取出來並裝到dataset裡就可以斷開程序與數據庫的連接了,此時可以對dataset裡數據處理).

那麼要實現上面所說的,就有一個關鍵的問題.我們知道程序可以與數據庫連接並讀取數據,但是把這些讀取到的數據怎麼裝到dataset裡呢?用前面的知識,我們知道可以用SqlDataAdapter裡的read()方法,讀一行,然後在把每行的數據按字段名取出來,一個一個的添加到dataset裡的datatable中.這個過程要求datatable先創建列,然後再一行一行往裡添加SqlDataAdapter.read()方法讀取的數據.這樣也可以把數據裡的數據添加到dataset裡,但是本質還是手工往dataset中的datatable裡添加數據.(手工添加,就是用代碼在datatable裡創建列,再加行的意思).要是都是這樣來把數據庫裡的數據裝到dataset中是不是太麻煩了!現在我們就想一下把數據庫裡的很多記錄甚至一張表裡的數據,一下裝到datatable裡,不要一行一行的手工添加進去,這樣又方便又高效.為了滿足這樣一個願望,SqlDataAdapter類就引出來了.

SqlDataAdapter類,可以把數據庫裡的數據讀出來,然後把這些數據一下就裝到了dataset中.而且還可以把dataset裡的數據一下又裝到數據庫裡(或更新到數據裡).那麼SqlDataAdapter類是不是就相當於dataset與數據庫只之間的橋梁? 像這樣:dataset------SqlDataAdapter-------數據庫

SqlDataAdater如何將數據裝到dataset裡呢?它有個重要的方法叫:SqlDataAdater.Fill(...).調用這個方法的時候就可以把數據填充到dataset裡的,這個方法的參數,看一下文檔就知道了.可以直接填到一個datatable裡如:Fill(datatable)也可以這樣Fill(dataset).等等.不管怎麼樣,數據最終是存在datatable裡的.SqlDataAdater怎麼從數據庫裡得到數據呢?第一篇文章講了程序如何與數據庫操作,說到一個類叫:SqlCommand,它就是負責傳遞命令給數據庫的.要想得到數據庫的數據肯定也要用這個傳遞命令,而且上傳遞一個查詢的命令.然後SqlDataAdater可以支配這個SqlCommand.當數據庫得到SqlCommand傳來的命令後執行查詢命令,並返回查詢的數據.SqlDataAdater此時就可以把這些數據庫返回的數據填充到了datatable裡了.

看一段代碼,以sql2000中Northwind數據庫為例.

Code1

1   static DataSet ds;
2   protected void Page_Load(object sender, EventArgs e)
3   {
4     if (!Page.IsPostBack)
5     {
6       bindGridView();
7     }
8   }
9   public void bindGridView()
10   {
11     string strSql = "select employeeid,firstname,city,country from Employees";
12     SqlConnection cn = new SqlConnection();
13     cn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
14
15     ds = new DataSet();
16
17     SqlCommand cmd = new SqlCommand(strSql, cn);
18
19     SqlDataAdapter da = new SqlDataAdapter();
20
21     //SelectCommand表示是SqlCommand傳送給數據庫的是查詢語句
22     da.SelectCommand = cmd;
23
24     //開始發送命令(SqlCommand)給數據庫,把返回的數據填充到dataset裡的表名叫table1的datatable裡
25     da.Fill(ds, "table1");
26
27     //上面已經把ds裡的table1填充上數據了,所以可以綁定到table1
28     GridView1.DataSource = ds.Tables["table1"].DefaultView;
29     GridView1.DataBind();
30
31   }
32

上面代碼就可以完成一次從數據庫讀取數據並填充到dataset裡.看了上面一個代碼可發現一個問題?沒有調用cn.open()方法,怎麼連上數據庫的.前面不是講必須調用cn.open()方法才能連上數據庫嗎?在這裡其實也調用了,只不過是SqlDataAdapter會自動的完成,不需要我們來顯示的操作了.也就是SqlDataAdapter能自動打開連接.SqlDataAdapter不僅能自動打開一個連接,而且,它還能控制SqlCommand發送命令.再看da.Fill(ds, "table1")總參數是什麼意思,是把數據填充到ds的table1裡.ds裡有名為table1的表嗎?我們創建ds的時候並未添加表.這個也是SqlDataAdapter控制的.da.Fill(ds, "table1")其實是往ds中名為table1的表中加數據,如果沒有這個表就自動創建一個名叫table1的表.

可見da.Fill(ds, "table1")方法需要完成事還挺多的,需要完成的事有:1、打開一個連接;2、發配SqlCommand去數據庫;3、把數據庫返回的數據填充到ds裡,還指定了往ds的哪個表裡裝數據;4、關閉連接.由此看來SqlDataAdapter是挺忙的.

我們再看如下代碼:

Code2

1   static DataSet ds;
2   protected void Page_Load(object sender, EventArgs e)
3   {
4     if (!Page.IsPostBack)
5     {
6       bindGridView();
7     }
8   }
9   public void bindGridView()
10   {
11     string strSql = "select employeeid,firstname,city,country from Employees";
12     SqlConnection cn = new SqlConnection();
13     cn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
14
15     ds = new DataSet();
16
17     //SqlCommand cmd = new SqlCommand(strSql, cn);
18
19     SqlDataAdapter da = new SqlDataAdapter(strSql,cn);
20
21     //SelectCommand表示是SqlCommand傳送給數據庫的是查詢語句
22     //da.SelectCommand = cmd;
23    
24     //開始發送命令(SqlCommand)給數據庫,把返回的數據填充到dataset裡的表名叫table1的datatable裡
25     da.Fill(ds, "table1");
26
27     //上面已經把ds裡的table1填充上數據了,所以可以綁定到table1
28     GridView1.DataSource = ds.Tables["table1"].DefaultView;
29     GridView1.DataBind();
30
31   }
32

運行後發現也可以,效果和上面的是一樣.但是沒有SqlCommand對象啊,誰把查詢命令傳遞給數據庫呢?(SqlCommand是用來傳遞命令的).其實這是另一中寫法.也就是在創建SqlDataAdapter對象的時候,給了兩個參數strsql和cn,這樣在SqlDataAdapter內部就會自動生成SqlCommand對象.最終發送命令的還是SqlCommand對象,SqlDataAdapter對象是不能通知數據庫的(這是我猜測的).

上面代碼運行後通過gridview可以發現,顯示出來的字段名和數據庫表中的字段名是一樣的(employeeid等).有時我們想在datatable中的字段名改下,怎麼做?在SqlDataAdapter有個叫做映射的東西,什麼叫映射?簡單的理解就是誰對應誰的意思,在這當然是數據庫表字段的名稱對於datatable中的字段的名稱.比如說在數據庫表裡的字段名為:employeeid.這個字段對應的在datatable中的字段名叫id號.這就是映射的意思.如何用映射關系呢?是在SqlDataAdapter中添加的,SqlDataAdapter裡可以有很多組映射,一個表嘛添加一個映射就行了,然後設置所對應的字段的映射名.

看如下代碼:

Code3

1   static DataSet ds;
2   protected void Page_Load(object sender, EventArgs e)
3   {
4     if (!Page.IsPostBack)
5     {
6       bindGridView();
7     }
8   }
9   public void bindGridView()
10   {
11     string strSql = "select employeeid,firstname,city,country from Employees";
12     SqlConnection cn = new SqlConnection();
13     cn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
14
15     ds = new DataSet();
16     SqlDataAdapter da = new SqlDataAdapter(strSql,cn);
17
18     //添加一個映射,源表名為:employees,dataset裡表名稱為:table1
19     da.TableMappings.Add("employees", "table1");
20     //字段名稱的對應關系
21     da.TableMappings[0].ColumnMappings.Add("employeeid", "id號");
22     da.TableMappings[0].ColumnMappings.Add("firstname", "姓名");
23     da.TableMappings[0].ColumnMappings.Add("city", "城市");
24     da.TableMappings[0].ColumnMappings.Add("country", "國家");
25
26     //如果添加了映射,那麼da.Fill(ds,源表名)方法的第二個參數必須和da.TableMappings.Add("employees", "table1")第一個參數相等
27     da.Fill(ds, "employees");
28
29     //上面已經把ds裡的table1填充上數據了,所以可以綁定到table1
30     GridView1.DataSource = ds.Tables["table1"].DefaultView;
31     GridView1.DataBind();
32
33   }
34

上面代碼就添加了一組映射關系,無須解釋了,一看便知道什麼意思.運行後發現,在gridview上,列名顯示的就是id號,姓名,城市,國家了,而不是源表中的英文了.當然dataset裡表"table1"的列名就是映射這些名字.

值得注意的是在添加映射的時候da.TableMappings.Add("employees", "table1")中第一個參數,也就是源表名可以隨便寫的,比如寫成adb,123都可以,但是這裡怎麼寫,da.Fill(ds, "employees")中第二個參數就要怎麼寫.否則出錯.為什麼可以隨便寫,這個好理解嘛,我只要知道你源表裡的字段就行了,你表名我又不管你,要映射的是字段名稱.表名隨便寫就隨便寫,只要字段確實是原來那字段就行了.當然如果把原來的字段也隨便寫了如:da.TableMappings[0].ColumnMappings.Add("abc", "id號")那麼這個字段的映射就不起作用了,源表總並無abc這個字段.gridview上面這個字段顯示的還是employeeid.再一,da.TableMappings.Add("employees", "table1")中第二個參數的意思是要映射的dataset裡datatable的名稱,如果沒有這個名稱的表,那麼就創建一個.可見gridview綁定到dataset裡的哪個表也要與映射的表名(table1)一致.

上面講了如何用SqlDataAdapter把數據庫裡的數據填充到dataset中以及列的映射.下面我們看看如何把dataset裡的數據更新到數據庫表中.

我們先從數據庫表裡讀取數據,然後把這些數據填充到dataset裡.接著我們把dataset裡的數據修改一下,再把此時修改後的dataset裡的數據更新到數據中

看一段代碼:

Code4

1   protected void Button5_Click(object sender, EventArgs e)
2   {
3     SqlConnection cn = new SqlConnection();
4     cn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
5
6     SqlDataAdapter da = new SqlDataAdapter();
7     //頁面一打開ds中的table1已經被填充上數據了,下面把table1中字段為"國家"的值改為china,每行都改.
8     foreach (DataRow dr in ds.Tables["table1"].Rows)
9     {
10       dr["國家"] = "CHINA";
11     }
12     //指定是更新命令,SqlCommand用的是匿名對象@country表示它為參數
13     da.UpdateCommand = new SqlCommand("update employees set country=@country", cn);
14
15     //在上面的SqlCommand中加一個參數,並指定這個參數的值等於ds裡table1的"國家"字段下的值
16     da.UpdateCommand.Parameters.Add("@country", SqlDbType.VarChar, 50, "國家");
17
18     //設定SqlCommand發送命令給數據庫,數據庫執行命令後不返回執行命令的情況(不加這行會出錯)
19     da.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;
20    
21     //設置數據庫每次更新的行數,此處設置為9行
22     da.UpdateBatchSize = 9;
23
24     //開始更新,把ds中table1裡的數據更新到數據裡
25     da.Update(ds,"table1");
26
27   }
28

上面的代碼一執行就就可以更新數據庫了.看起來好象不好理解.怎麼理解呢?

1,table1裡的數據是從數據庫裡讀取到的,我們把table1裡的某列("國家")下的值修改了,也就上面那個循環

2,用sqlcommand傳遞更新語句給數據庫,那更新的值為多少呢?用了一個參數(參數是sqlcommand裡添加的,應用sql語句封裝在sqlcommand裡面),這個參數可以指定用datatable中那一列,上面代碼指定的是"國家"了

3,設置與數據庫一次更新幾行.這裡如果設置為1,表示sqlcommand發送一次命令給數據庫,數據庫只更新一行,然後再發送一次,數據再更新一行,table1裡有幾行就發送幾次,直到每行都更新完.不是說執行完了,數據庫只更新了一行.而是把table1裡的每行都更新到數據裡了,不過是一次一次的更新的.顯示一次更新多行的效率比較高.

4,怎麼更新呢?第25行就把table1裡的數據更新到了數據裡.(其實更新語句就是sqlcommand裡的sql語句,只是添加參數並把參數的值對應到table1裡的某列時不好形象的理解)

看著糊塗,動手寫遍代碼就清楚了.

我們再來看看如何增加一條記錄到數據裡其實和上面是一個原理,我們把dataset中的datatable添加一行,然後用SqlDataAdapter把dataset更新到數據裡,數據庫也就添加一行了.

代碼如下:

Code6

1   protected void Button4_Click(object sender, EventArgs e)
2   {
3     string strSql = "insert into employees(firstname,city,country,lastname) values(@firstname,@city,@country,@lastname)";
4     SqlConnection cn = new SqlConnection();
5     cn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
6
7     SqlDataAdapter da = new SqlDataAdapter();
8     da.InsertCommand = new SqlCommand(strSql, cn);
9
10     da.InsertCommand.Parameters.Add("@firstname", SqlDbType.VarChar, 50, "姓名");
11     da.InsertCommand.Parameters.Add("@city", SqlDbType.VarChar, 50, "城市");
12     da.InsertCommand.Parameters.Add("@country", SqlDbType.VarChar, 50, "國家");
13
14     //下面三行代碼有點意思
15     SqlParameter sp = new SqlParameter("@lastname", SqlDbType.VarChar, 50);
16     sp.Value = "小三";
17     da.InsertCommand.Parameters.Add(sp);
18
19     //下面就往table1裡添加一條記錄了
20     DataRow dr = ds.Tables["table1"].NewRow();
21     dr["姓名"] = "張三";
22     dr["城市"] = "合肥";
23     dr["國家"] = "中國";
24     ds.Tables["table1"].Rows.Add(dr);
25     //此時的table1是多一條記錄的更新到數據裡
26     da.Update(ds, "table1");
27
28     GridView1.DataSource = ds.Tables["table1"].DefaultView;
29     GridView1.DataBind();
30
31   }
32

上面就添加了一行數據到數據庫裡,添加了四個字段的值.看15,16,17行代碼,挺有意思.

我們說把dataset跟新到數據庫裡.其實就是在構建sql語句的時候,指定sql語句中參數的值來自dataset裡,並指定到具體的哪列.看10,11,12行代碼,指定了@firstname,@city,@country三個參數的值來自dataset裡表table1裡的三列(姓名,城市,國家).table1裡只有三個字段,是不是就只能更新數據表裡三個字段呢?非也.這兩個是沒有關系的.雖然table1裡只有三個字段,但是我也可以更新數據庫表裡的多個字段,上面代碼中table1裡並沒有lastname這個字段,那麼我要更新的數據庫的值我不用table1裡的是了,我自己隨便設個("小三").@lastname參數,添加到sqlcommand裡就行了.sqlcommand在哪?就是da.InsertCommand啊!

上面無非在說,我們可以把sql語句中的參數需要的值等於dataset裡的數據,然後會自動對應到我們設好的列上(像10,11,12行樣),當然我們不用dataset的數據作為參數的值當然可以.上面代碼運行後發現,gridview中所顯示的新添加的行,列"id號"上沒有值,大家自己想想為什麼,很簡單的.

突然發現對於sqlcommand參數這部分前面的文章沒有講,不過不難,看看就知道了.......

下面我們來看看SqlDataAdapter.Fill(dataset,int類型,int類型,string類型)方法中有四個有趣的參數.這個四個參數是什麼意思呢?,第一個要填充的dataset,第二個的意思是從第幾條記錄開始填充,第三個的意思是填充的記錄數,第四個源表的名稱.比如:Fill(dataset,0,1,"table1")是什麼意思呢?就是往dataset裡的table1裡填充數據,從數據庫裡讀取的數據中,從第0條開始填充,填充1條.那麼dataset裡被裝了幾條記錄,當然是一條.

上面一段話,我能想到什麼?我們可以從數據裡讀取若干條的記錄,然後指定從哪條開始填充幾條到dataset中,而不是把從數據庫讀取的數據全部填充到dataset中.我們可以想到分頁效果,是不是?比如:我們第一次把數據庫表中數據讀取出來,然後把第0條記錄裝到dataset裡,點"下一頁"再把數據庫表裡數據讀出來然後把第1條裝到dataset裡.依次類推是不是就可以完成分頁效果了.我們用代碼來說明.

代碼如下:

Code8

1   int maxCount = 9;  //最大頁數,當然我數據裡只有9條記錄所以這麼寫,一般都是查詢下數據裡的記錄總數
2   static int pageN = 0;  //第幾頁的意思,0就第0條記錄,1就是第一條記錄嘛.
3   static DataSet ds;
4   protected void Page_Load(object sender, EventArgs e)
5   {
6     if (!Page.IsPostBack)
7     {
8       //頁面第一次加載,顯示第0條記錄(第一頁)
9       bindGridView(0);
10     }
11   }
12   public void bindGridView(int pageN)
13   {
14     string strSql = "select employeeid,firstname,city,country from Employees";
15     SqlConnection cn = new SqlConnection();
16     cn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
17
18     ds = new DataSet();
19     SqlDataAdapter da = new SqlDataAdapter(strSql,cn);
20
21     //添加一個映射,源表名為:employees,dataset裡表名稱為:table1
22     da.TableMappings.Add("employees", "table1");
23     //字段名稱的對應關系
24     da.TableMappings[0].ColumnMappings.Add("employeeid", "id號");
25     da.TableMappings[0].ColumnMappings.Add("firstname", "姓名");
26     da.TableMappings[0].ColumnMappings.Add("city", "城市");
27     da.TableMappings[0].ColumnMappings.Add("country", "國家");
28
29     //往ds裡填充數據,在從數據庫中讀取的記錄中從第pageN開始填充,填充1條
30     da.Fill(ds, pageN, 1, "employees");
31
32    
33     GridView1.DataSource = ds.Tables["table1"].DefaultView;
34     GridView1.DataBind();
35
36   }
37   //上一頁
38   protected void Button1_Click(object sender, EventArgs e)
39   {
40     if (pageN >= 0)
41     {
42       pageN--;
43       if (pageN < 0)
44       {
45         pageN = maxCount - 1;  //最後一頁
46       }
47       bindGridView(pageN);
48
49     }
50   }
51   //下一頁
52   protected void Button2_Click(object sender, EventArgs e)
53   {
54     if (pageN < maxCount)
55     {
56       pageN++;
57       if (pageN == maxCount)
58         pageN = 0;
59
60       bindGridView(pageN);
61
62     }
63   }
64

上面代碼就是簡單的分頁,每次顯示一頁的.原來很簡單.每次往dataset裡裝一條記錄,下一頁就往dataset裡裝下一條記錄,上一頁就往dataset裡裝上一條記錄.

要注意,從數據庫讀出的記錄SqlDataAdapter是把這些記錄從0開始記數的.比如數據庫裡讀9條記錄,那麼SqlDataAdapter把這9條記錄表示為0~8.所以上面代碼第45行要減一. 上一頁,下一頁裡的代碼看不懂,單步調試一下就差不多搞清楚了(這個也不好解釋).

這種分頁其實並不常用,因為牽涉到效率問題,你想啊,每次翻頁的時候SqlDataAdapter都要把表裡的數據都讀出來然後只要一條記錄(填充到dataset裡).是不是對性能有一定的影響.數據庫表裡記錄少還好,要是多,那就做了很多無用功了.

忘了講一個問題,就是當我們更新dataset裡的數據到數據裡時,有的字段不想讓他改變,比如id號,我們並不想讓它改變

這樣update employees set firstname=@firstname,city=@city,country=@country where employeeid=@employeeid

employeeid我們並不想讓它,而我們在dataset更改了它怎麼辦?肯定更新到數據庫裡會出錯的.可以這樣解決,看下面代碼

Code7

1     string strSql="update employees set firstname=@firstname,city=@city,country=@country where employeeid=@employeeid";
2     SqlDataAdapter da = new SqlDataAdapter();
3     da.UpdateCommand = new SqlCommand(strSql, cn);
4
5     SqlParameter sp = da.UpdateCommand.Parameters.Add("@employeeid", SqlDbType.Int);
6     sp.SourceColumn = "id號";
7     sp.SourceVersion = DataRowVersion.Original;
8
第7行的意思是:設置datarow中行的版本為原始值.什麼意思?就把datast裡id號字段的值改了,它用是它未改前的值(原始值).也就是確保了id為原來的id,讓修改無效.

不講了,真累人.今天就講這麼多.感覺這次講的最不好..............

下次再講把.

還有並發控制,2.0部分新特性,對xml的操作,事物處理,數據緩存,SQLCRL,零碎知識.等等...等等...

越講越多,講不完了!!!!!!!!!!

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