前面我們介紹了EF4對數據的增刪改查的操作。可以借助於EF4,開發人員的工作量將變得特別簡單。
這次我們介紹EF4的數據綁定功能。這次你將會發現EF4的更加簡單方面的又一用途:即EF4作為數據源控件的“數據源”。
汗!!好拗口喲。為什么這么說呢?
因為當我們在項目中使用數據源控件時,是需要指出給該數據源控件從哪里取數據的,即指出數據源控件的數據源。以前我們會用Dataset作為數據源控件的數據源。然后,由Dataadapter與數據庫交互,把數據填充到Dataset中。再呈現到顯示控件上(如datagridview)。這次我們使用EF4的來代替以前Dataadapter與dataset所一起完成的任務。我們已經知道:EF4是可以把數據表的記錄映射成實體與實體集合,並且可跟蹤管理這些實體。那么我們就可以把這些實體和實體集合作為數據源控件的數據源。這樣數據源控件不需要直接和數據庫打交道,而是和EF4的實體容器(Container)交互,再由EF4和數據庫交互。
======================================================
好了,我們先啟動VS2010.
1. File->new-->Windows form project。(名字:EFDataBindingDemo)
2. 在解決方案上,右鍵--》添加--》新項目--》類庫。(名稱:EFData)。(我們為體現分層的思想,這次把*.EDMX文件單獨建立到一個類庫項目中。),
3. 在EFData類庫項目上面右鍵--》添加--》ADO.Net entity data model 。(名稱:Northwind)。點擊“確定”,如下圖:

4.找到服務器上的northwind數據庫。如下圖:

5.選擇三張表:Category,Product,Supplier。如下圖:

6.在EFDataBindingDemo項目中添加項目引用:如下圖:(同時別忘了把EFData項目中的App.config文件也烤貝到EFDataBindingDemo的項目下面。最簡單的方法是你可以直接用鼠標把該文件拖拽到EFDataBindingDemo的項目中)

7.添加.NET類庫引用,如下圖:

8. 選中EFDataBindingDemo項目,然后打開數據源窗口,如下圖:

9.點擊數據源窗口上,最左邊的的按鈕--》添加數據源:如現數據源類型供選擇,如下圖:

10.點擊Next,如下圖:如果出現空白,說明你的*.EDMX忘記了編譯,

選擇“取消”。編譯EFData項目,然后重新添加數據源,到這一步。
注意:當你用鼠標選中“EFData”項目時,數據源窗口顯示的是“EFData”項目的數據源;只有你選中EFDataBindingDemo項目時,數據源窗口顯示的才是EFDataBindingDemo項目的數據源。不要混淆了。
11.重新選中EFDataBindingDemo項目,在數據源窗口--》添加數據源,重復步驟9,如下圖:

12.此時數據源窗口會顯示添加過的數據源:如下圖:

13.拖拽“product”數據源節點,到form1上面,松開鼠標。如下圖:(注意觀察圖中5個標號,這是自動添加)

14.運行程序:如下圖:

說明:沒有取到數據,很失望吧?呵呵,之前我們用指向dataset的數據源綁定控件時,是主動從數據庫往外取,所以是可以加載到數據的。但是現在我們不是直接使用數據庫,而是使用EF4(其實就是使用EF4的容器),再有EF4與數據庫打交道。因為,我們的所有實體都是放到context容器中的,而現在我們並沒有創建這個容器啊,所以加載不到數據(實體)。
15.我們在窗體的Load事件中添加下面的代碼:
1 private void Form1_Load(object sender, EventArgs e)
2 {
3 var context = new NorthwindEntities();
4 ObjectResult<Product> products = context.Products.Execute(MergeOption.AppendOnly);
5 // 給數據源控件的數據源屬性賦值。
6 this.productBindingSource.DataSource = products;
7 }
運行程序,如下圖:(數據是加載了,但是Category,和Supplier兩列的數據只有類型,沒有實際數據值)

16.在productDataGridView上面右鍵——》edit columns;添加兩列CategoryName和SupplierContactNameName,如下圖:(每列的Name和HeaderText設置相同)把新添加的列移到最下端,方便查看。

在productDataGridView控件的RowPrePaint事件中添加如下代碼:
1 private void productDataGridView_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
2 {
3 if (e.RowIndex < productBindingSource.Count)
4 {
5 var prod = (Product)productBindingSource[e.RowIndex];
6
7 var grid = productDataGridView;
8 if (prod.Category != null)
9 {
10 grid.Rows[e.RowIndex].Cells[CategoryName.Index].Value = prod.Category.CategoryName;
11 }
12
13 if (prod.Supplier != null)
14 {
15 grid.Rows[e.RowIndex].Cells[SupplierContactName.Index].Value = prod.Supplier.CompanyName;
16 }
17 }
18 }
17.運行代碼:如下圖:(圖中的兩個紅框分別是:處理前的列和處理后的列)

18. 使用添加、刪除、保存功能:
productDataGridView控件的右上方有一個黑色的小小實心三角形,叫“智能標記”。點開智能標記,設置里面的Enable Adding,Enable Editing, Enable Deleting,為選中狀態。
窗體上方的導航條,有三個圖標:添加,刪除,保存。分別用鼠標右鍵-》Enable 。把它們選為可用。分別為這三個圖標添加click事件(在上面雙擊,即可)
我們把窗體load事件中定義的context移到類中,這樣多個方法都可以使用這個context變量。
添加,刪除按鈕是直接對productBindingSource進行了修改。而productBindingSource會直接影響productDataGridView的變化。這些我們都不必處理。
下面我們處理保存按鈕事件:代碼如下:
1 private void productBindingNavigatorSaveItem_Click(object sender, EventArgs e)
2 {
3
4 try
5 {
6 this.productBindingSource.EndEdit();
7 context.SaveChanges();
8 MessageBox.Show("save successfuly");
9 }
10 catch (Exception ex)
11 {
12 if (ex.InnerException != null)
13 MessageBox.Show(ex.InnerException.Message.ToString());
14 else
15 MessageBox.Show(ex.Message.ToString());
16 }
17
18 }
運行程序,這時你可以進行添加、修改和刪除,然后保存到數據庫中。
(注意:
1.在刪除Product時,可能會引發異常,因為數據庫中有Order_detail表的外鍵引用了product中的主鍵。所以,你只能刪除那些沒有被其它表引用到的product。
2.一般情況下,在界面顯示時,我們是不讓用看到ID號的,因為這些對用戶來說沒有意義,所以我們在實際項目中最好把這一ID列(無論是主鍵列還是外鍵列)全部隱藏掉。看清是隱藏掉,不是刪除掉,因為我們在程序中是要使用這些ID號進行CRUD的操作的。
3. 在處理更新的某一個單元格的數據的時候。我遇到了困惑:以前使用dataset作數據綁定時,是直接可以把對單元格的修改反饋到數據庫中的,而這次我使用EF時,卻不能把對單元格的修改反饋到數據庫了,即使我調用了context.savechanges()方法。后來我找了許多資料,也沒能解決問題。在我一次偶然的測試中,我一次性修改了多個單元格,然后保存。這次竟然保存成功了。感覺是因為我對單元格作的修改量太小了,context並沒有把它們及時更新入數據庫中,而是對這些進行了本地緩存的原因。但我只是猜測,並不確定。希望高人給我指點一下。、謝謝。)
可以看到,我們可以非常輕松地處理這些數據了。是不是感覺世界又美好了許多。哈哈。
窗體后台完整代碼如下:
窗體后台完整代碼
1 public partial class Form1 : Form
2 {
3 NorthwindEntities context;
4
5 public Form1()
6 {
7 InitializeComponent();
8 }
9
10 private void Form1_Load(object sender, EventArgs e)
11 {
12 context = new NorthwindEntities();
13 ObjectResult<Product> products = context.Products.Execute(MergeOption.OverwriteChanges);
14 // 給數據源控件的數據源屬性賦值。
15 this.productBindingSource.DataSource = products;
16
17 }
18
19 private void productDataGridView_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
20 {
21 if (e.RowIndex < productBindingSource.Count)
22 {
23 var prod = (Product)productBindingSource[e.RowIndex];
24
25 var grid = productDataGridView;
26 if (prod.Category != null)
27 {
28 grid.Rows[e.RowIndex].Cells[CategoryName.Index].Value = prod.Category.CategoryName;
29 }
30
31 if (prod.Supplier != null)
32 {
33 grid.Rows[e.RowIndex].Cells[SupplierContactName.Index].Value = prod.Supplier.CompanyName;
34 }
35 }
36 }
37
38
39
40 private void productBindingNavigatorSaveItem_Click(object sender, EventArgs e)
41 {
42
43 try
44 {
45 this.productBindingSource.EndEdit();
46 context.SaveChanges();
47 MessageBox.Show("save successfuly");
48 }
49 catch (Exception ex)
50 {
51 if (ex.InnerException != null)
52 MessageBox.Show(ex.InnerException.Message.ToString());
53 else
54 MessageBox.Show(ex.Message.ToString());
55 }
56
57 }
58
59
60 }
