Entity Framework4.0 (八) EF4的数据绑定(转 )
前面我们介绍了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事件中添加下面的代码:
private void Form1_Load(object sender, EventArgs e) { var context = new NorthwindEntities(); ObjectResult<Product> products = context.Products.Execute(MergeOption.AppendOnly); // 给数据源控件的数据源属性赋值。 this.productBindingSource.DataSource = products; }
运行程序,如下图:(数据是加载了,但是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 }