大家有兴趣可以看看自动在Customers.Designer.cs文件里生成的代码,一切的一切Visual Studio都给你生成了。定位到NewCustomer()方法可以看到它有个[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, false)]属性,这是设置让ObjectDataSource,BindSource等数据源控件自动绑定相应操作的属性,估计用的是一种Ioc(控制反转)的机制来实现的,你在设置ObjectDataSource的时候它的插入方法会自动绑定到这个方法上,一会儿就会看到。
以上我们把显示消费者列表,以及消费者的修改,删除,添加等持久化操作代码生成了,我们还没有写一行代码,包括SQL语句哦。我们的数据实体(强类型数据集的ROW)虽然是哑对象,但是我们的表适配器可以以托管的形式来对这些实体进行CRUD持久化操作,类似于CMP(容器托管持久化,这里的表适配器就相当于容器)模式,然后我再告诉大家如何给数据实体添加自定义业务逻辑的方法(也许一个方法不能算是一个Case,但我感觉获取消费者的订单至少是一个Action吧)。当然了,我这里告诉大家的只是一种紧耦合的方法,如果你想设计灵活度比较高的高度可伸缩的应用,尽量使用一些Interface,Service,Event,properties(自定义属性)等技术来实现数据实体和数据实体具体操作的松散耦合,这样就可以做到我在UI层只引用Customer这个业务实体,然后调用Customer.GetOrderDetails()方法的时候,也许是在本地DLL里实现,也许是在用Rmorting方式连接到Application Server来实现,也许是通过一个叫做GetOrderDetailsByCustomerID的Web服务来实现的。
现在我们来做一个订单细目的业务实体以及获取某个消费者订单细目的操作,因为Northwind数据库里没有这么一个直接的表来直观的显示订单细目,Orders只是一个交叉引用表,Order Details表也是一个交叉引用表,而我们的订单细目要显示订单号,消费者名称,产品名称,购买数量,单价,雇员名称等信息,而这些信息分布在多个表中,我们不能简单的把一个表拖放到数据集设计视图来生成相应的业务实体和表适配器。我们可以在数据集设计视图里的空白处右键选择【Add TableAdapter】,然后按向导在【Quert Builder】里把Customers,Orders,Order Details,Procucts,Employees五个表拖到数据表栏上,然后他们之间的外键关系会自动的可视化的指定,然后分别用鼠标选择几个表的某些字段,最后生成语句如下。
SELECT Customers.CustomerID, Customers.ContactName, [Order Details].UnitPrice, [Order Details].Quantity, Products.ProductName, Orders.OrderID,
Orders.OrderDate, Employees.FirstName + Employees.LastName AS fullname
FROM Customers INNER JOIN
Orders ON Customers.CustomerID = Orders.CustomerID INNER JOIN
[Order Details] ON Orders.OrderID = [Order Details].OrderID INNER JOIN
Products ON [Order Details].ProductID = Products.ProductID INNER JOIN
Employees ON Orders.EmployeeID = Employees.EmployeeID
WHERE (Customers.CustomerID = @CustomerID)
ORDER BY Customers.CustomerID DESC |
方法名修改成“GetOrderDetailsByCustomerID”,并把生成的强类型表重命名为OrderDetails。
另外在表适配器向导里有一个【advert】按钮,点击打开后可以设置本查询是否支持乐观并发锁定等处理,因为在一个多用户的数据应用里进行删除和修改操作的时候要考虑并发问题的,这个是个很棘手的问题,Visual Studio也帮我们解决了(具体原理我还不太清楚,我没有详细研究数据集自动生成的代码,一般是用时间戳列或者 一长串where子句来处理并发的。)
目前为止,我们仍然一行代码也没有写,不过现在要写一些了。双击空白处,打开Customers.cs文件。可以看到Customer类有个partial修饰符,这也是.NET 2.0的新特性,因为Customer这个类一半在Customer.Desinger.cs里,而另一半分布在Customer.cs里,你重新修改了表适配器,会自动同步Customer.Desinger.cs里代码,而你自己写在Customer.cs里的代码不会给你覆盖,看来.NET 2.0的新特性考虑还是很体贴的。以前我们只能由代码生成器生成一个基类,然后手工把自定义代码写到一个子类里,以防止代码生成器重新生成代码的时候把你自己写的代码覆盖掉,对框架和架构感兴趣的朋友也许看过《.NET企业应用高级编程》里的那个WEO体系结构和ObjectBuilder代码生成工具。我们可以在Customer类里添加OnColumnChanging,OnRowChanging等方法来进行数据完整性的验证,详见MSDN,这里不做重点讲解。
因为默认生成的GetOrderDetails方法是一个非静态方法,使用起来有些不方便,为了便于使用,我们在Customer.cs里加入一下语句。用一个静态方法来重写(我也不知道是重载还是重写了)非静态方法GetOrderDetails。
partial class CustomersTableAdapter { public static Customer.OrderDetailsDataTable GetOrderDetails(string CustomerID) { typedDatasetSample.lib.CustomerTableAdapters.OrderDetailsTableAdapter o = new typedDatasetSample.lib.CustomerTableAdapters.OrderDetailsTableAdapter(); return o.GetOrderDetailsByCustomerID(CustomerID); } } |
因为默认生成的业务实体类是CustomersRow,我们来改进它,给它加一个自定义方法。(但是我感觉CustomersRow这个名字不好听,如果做一个它的子类叫CustomersEntity的话,可是子类又不能引用父类,所以这个问题我也不知道如何解决,所以先用分割类来添加一个新方法,而不是继承CustomersRow类然后给子类添加一个新方法)
partial class Customer { partial class CustomersRow { public Customer.OrderDetailsDataTable GetOrderDetails() { return CustomersTableAdapter.GetOrderDetails(this.CustomerID); } } } |
好了,这个类库就做到这里了,你当然可以添加其它一些业务逻辑,关闭这个项目。现在我们先创建一个typedDatasetSample.Web的网站。在解决方案里点击右键选择【Existing project】把刚才的数据集类库添加到网站解决方案里。然后在网站项目里右键选择【Add Reference】把typedDatasetSample.lib项目引用一下。
打开Default.aspx的设计视图,在ToolBox里拖放一个DetailView控件进来,重命名为CustomerDetailsView。点击右上角的小三角Choose Data Source,选择new data source,选择【object】就是添加一个ObjectDataSource,命名为CustomerObjectDataSource。点击【next】按钮后【choose your business object】里选择CustomersTableAdapter,下一步后选择CRUD操作的映射方法,前面我们说过一些方法加上[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, false)]属性就会自动在这里绑定,所以我们直接在这里设置一下就行了。因为在系统自动生成了一些CRUD方法,我们不用它们,我们用我们的自定义查询和方法,比如说NewCustomer()方法,而不是默认的Insert()方法,因为这个不直观。然后把Enable Paging,Instering,Editing,Deleteing的勾打上。因为Customers表里数据太多,我们把ObjectDataSource的FilterExpression属性设置成“ContactTitle='Owner'”以减少检索的数据,其实CustomerObjectDataSource就相当于一个实际的数据源,它有好多模仿数据源的特性,大家可以详细看看。在asp.net 2.0里可以让你不知不觉就使用了MVC模式。
好了,我们又没有写一行代码,按F5运行一下。看一下添加,删除,修改,浏览是不是都能用了呀,就是这么简单。其实如果我们把添加,删除,修改等业务逻辑用oracle实现一遍,其实我们的asp.net程序几乎不用修改代码,只重新换一下objectdatasource就可以了。
下面拖放一个GridView控件,命名为OrderDetailGridView。选中CustomerDetailsView然后在属性窗口,点击属性表头的闪电按钮,所有可用的时间就显示了,双击DataBound会在Default.cs文件里添加CustomerDetailsView_DataBound方法,这个事件是在Detail控件数据绑定的时候触发的,修改成以下的代码。
protected void CustomerDetailsView_DataBound(object sender, EventArgs e) { //获取当前的数据绑定项并强制转换为DataRowView类型 DataRowView drv = (DataRowView)CustomerDetailsView.DataItem; //如果当前是添加新项目状态的话,不会获取DataRowView引用,所以要加一个IF判断。 if (drv != null) { //获取row并强制转换成CustomerEntity业务实体类
typedDatasetSample.lib.Customer.CustomersRow customer =(typedDatasetSample.lib.Customer.CustomersRow)drv.Row;
//运行业务实体类的一个自定义方法并把返回结果作为GridView的数据源
OrderDetailGridView.DataSource = customer.GetOrderDetails();
//绑定GridView
OrderDetailGridView.DataBind(); } |
F5运行一下,看看GridView是不是自动绑定了,翻页看看GridView是不是显示每个客户的订单细目呢。
Asp.net的应用就开发完了,下面我们来开发一个桌面程序。关闭网站解决方案,创建一个typedDatasetSample.Win的windows应用程序,然后把typedDatasetSample.lib项目包含进去,并引用到typedDatasetSample.Win项目里。然后把一个DataGridView拖进来命名为customersDataGridView,并把Dock属性设置为fill,让它能填充满窗体。再拖一个BindSource进来命名为customersBindingSource,再拖一个CustomerTableAdapter进来并命名为ta,Visual Studio 2005支持几个简单从重构手段,其中包括重命名,所以你重命名控件名称的时候,它会自动帮你修改一些相关的代码,比较智能的。然后选择窗体,在事件窗格里双击Load事件,键入如下代码。
private void Form1_Load(object sender, EventArgs e) { this.customersBindingSource.DataSource = ta.GetData(); this.customersBindingSource.Filter = "ContactTitle='Owner'"; this.customersBindingSource.Sort = "Country DESC, Address ASC"; this.customersDataGridView.DataSource = customersBindingSource; } |
好了,按F5运行以下,看看DataGridView是不是被数据填充了呢。因为我个人对桌面程序不是太感兴趣,也没有很多经验,所以只演示一个数据填充的业务逻辑,其它的持久操作以及自定义操作,对WinForm感兴趣的朋友可以自己做一做,我这里是以写代码的方式来完成的数据填充,其实也可以以可视化的操作来完成数据网格的填充。
查看本文来源