posts - 65, comments - 283, trackbacks - 18, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

ObjectDataSoruce 系结 BusinessObject 控件

Posted on 2008-06-06 14:41 jeff377 阅读(1792) 评论(14)  编辑 收藏 所属分类: 服务器控件
摘要
在 ASP.NET 中,ObjectDataSoruce 控件是实现三层式的重要关键,我们可以透过 ObjectDataSoruce 控件使用的自订中间层商务对象。不过一般找到的范例都是直接系结中间层商务对象,虽然范例通常写得相当符合对象导向,可是在实际运用上有下列几个问题。

问题一:维护性不佳
例如 Employee 商务对象的 Update 方法,可能有下列二种写法
[写法一] Update 方法中,每个字段皆为自变量
Public Function UpdateEmployee(EmployeeID As Integer, LastName As String, FirstName As String, _
                                   Address As String, City As String, Region As String, _
                                   PostalCode As String) As Integer
参考:http://msdn.microsoft.com/zh-tw/library/ms178538(VS.80).aspx
 
[写法二] Update 方法使用强型别,每个字段对应到类别的属性
Public Function UpdateEmployee(employee As NorthwindEmployee) As Integer
参考:http://msdn.microsoft.com/zh-tw/library/ms227562(VS.80).aspx
 
可是实际上真能这样用吗?以[方法一]为例,若异动字段非常多,Update 方法的自变量不就多到吓死人;[方法二]使用强型别可以解决字段多的问题,不过字段增减时,都需要同时维护 NorthwindEmployee 类别不是很麻烦吗?当你的系统非常庞大时,例如有上千个窗体,当这些窗体若需同时新增一个字段时,那就需要同时更新上千个对应的类别,可能会搞到你疯掉。
 
问题二:批次异动问题
当 GridView 系结 ObjectDataSource 在编辑一笔记录时储存时,有时我们并不希望该笔数据马上异动回数据库,也就是执行 ObjectDataSoruce 的 Update 方法,但数据不要真正写回数据库;而是所有编辑的数据先被暂存,最后执行一个方法(例如 Save),才将这些多笔数据的异动同时写回数据。而 ObjectDataSource 在处理这部分的问题,也很难完成。
 
问题三:Mater-Detail 问题
有些窗体具 Mater-Detail 的关系(如订单),可是 ObjectDataSource 很难描述这种关系,因为 ObjectDataSource 的角色相当于 DataTable,而 Mater-Detal 是多个 DataTable 的集合,相当于 DataSet。也就是说需要有多个 ObjectDataSource 才能描述 Master-Detal 的关系,而这些 ObjectDataSource 的异动不能马上写回数据库,窗体的编辑动作都需要被暂存,当按下储存时才能将整个 DataSet 的异动同时写回数据库。
 
TBBusinessObject 及 TBObjectDataSource 控件
针对以上的问题,在此使用另一种方式来处理,让 ObjectDataSource 系结 BusinessObject 控件,而 BusinessObject 控件提供 DataSet 属性,来暂存 ObjectDataSource 产生的异动。而呼叫真正的中间层商务对象时,再将 BusinessObject 控件的 DataSet 属性传入,由中间层商务对象去异动数据库。
以下范例以 GridView 系结 ObjectDataSource,当 GridView 进行修改、删除的动作时,会透过 ObjectDataSource 来呼叫 BusinessObject 控件来进行异动,而这此异动并不会被写回数据库,而是异动 BusinessObject 控件的 DataSet 属性。
一般的作法为
GridView --> ObjectDataSoruce --> 中间层 BusinessObject
而这边的作法为
GridView --> ObjectDataSoruce --> BusinessObject 控件 --> 中间层 BusinessObject



在页面上放置 TBBusinessObject 控件及 TBObjectDataSource 控件,在 TBObjectDataSource 控件设定 BusinessObjectID="TBBusinessObject1" 系结至 TBBusinessObject 控件。

            <bee:TBBusinessObject ID="TBBusinessObject1" runat="server">
            
</bee:TBBusinessObject>
            
<bee:TBObjectDataSource ID="TBObjectDataSource1" runat="server" 
                OldValuesParameterFormatString
="original_{0}" RowIndex="-1"
                TypeName
="Bee.Web.WebControls.TBBusinessObject"
                BusinessObjectID
="TBBusinessObject1"
                TableName
="Employee">
            
</bee:TBObjectDataSource>

当 Page Load 时产生的一个 Employee 的 DataTable,并将 DataTable 加入 TBBusinessObject.DataSet.Tables。在 GridView 执行 Update 及 Delete 时,要去设定 TBObjectDataSource 的 RowIndex,使用可以异动到对应的 DataRow。

Partial Class _Default
    
Inherits System.Web.UI.Page

    
Protected Sub Page_Load(ByVal sender As ObjectByVal e As System.EventArgs) Handles Me.Load
        
If Not Me.IsPostBack Then
            
Dim oTable As Data.DataTable
            
Dim oColumn As Data.DataColumn
            
Dim oRow As Data.DataRow

            oTable 
= New Data.DataTable("Employee")

            oColumn 
= New Data.DataColumn("ID"GetType(String))
            oTable.Columns.Add(oColumn)
            oColumn 
= New Data.DataColumn("Name"GetType(String))
            oTable.Columns.Add(oColumn)
            oColumn 
= New Data.DataColumn("Tel"GetType(String))
            oTable.Columns.Add(oColumn)

            oRow 
= oTable.NewRow()
            oRow(
"ID"= "001"
            oRow(
"Name"= "張三"
            oRow(
"Tel"= "02-11111111"
            oTable.Rows.Add(oRow)

            oRow 
= oTable.NewRow()
            oRow(
"ID"= "002"
            oRow(
"Name"= "李四"
            oRow(
"Tel"= "02-22222222"
            oTable.Rows.Add(oRow)

            oRow 
= oTable.NewRow()
            oRow(
"ID"= "003"
            oRow(
"Name"= "王五"
            oRow(
"Tel"= "02-33333333"
            oTable.Rows.Add(oRow)

            TBBusinessObject1.DataSet.Tables.Add(oTable)
            GridView1.DataBind()
        
End If
    
End Sub


    
Protected Sub GridView1_RowCommand(ByVal sender As ObjectByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView1.RowCommand
        
Select Case e.CommandName
            
Case "Update"
                TBObjectDataSource1.RowIndex 
= CInt(e.CommandArgument)
            
Case "Delete"
                TBObjectDataSource1.RowIndex 
= CInt(e.CommandArgument)
        
End Select
    
End Sub

End Class

执行程序,GridView 会透过 TBObjectDataSource 的来取得 TBBusinessObject 中的 Employee DataTable 并显示在 GridView 中。



按下编辑钮,针对数据列进行编辑


按下更新钮,异动就会被写回 TBBusinessObject 中的 Employee DataTable。

当按下删除钮时,TBBusinessObject 中的 Employee DataTable 的该笔 DataRow 也会被删除。



范例程序下程:BusinessObjectControl.rar

Feedback

#1楼    回复  引用  查看    

2008-06-06 16:07 by WCF群组博客      
强型别非常不灵活,
我主要是受Scott Mitchell 的那75篇Data Access Tutorials 的影响
使用TYPED DATASET结果吃尽苦头

#2楼    回复  引用  查看    

2008-06-06 18:53 by JesseZhao      
Scott 的那75篇Data Access Tutorials太毒了

#3楼    回复  引用  查看    

2008-06-06 18:53 by JesseZhao      
真是改变了咱们这一群的看法啊

#4楼    回复  引用  查看    

2008-06-06 19:34 by 金色海洋(jyk)      
若类型不是也挺好玩的吗?强类型,真的强了吗?

#5楼    回复  引用  查看    

2008-06-07 07:57 by BAsil      

#6楼    回复  引用  查看    

2008-06-07 19:59 by Vincent Yang      
@WCF群组博客
请举出具体例子,否则这种话说了太没意义了,而且不同size的project试用场景都是不同的。

#7楼    回复  引用  查看    

2008-06-08 03:52 by nicye      
个人认为,对于数据绑定,弱类型方便得多

问题一所述的问题不是问题,参数多了或添加参数,直接加个 <InsertParamter 就可以了

#8楼 [楼主]   回复  引用  查看    

2008-06-09 12:46 by jeff377      
@nicye
不可能只多了 InsertParamter 就可以,你沒有去更改 Insert 方法的相關參數怎麼可能會處理到該欄位。

#9楼    回复  引用  查看    

2008-06-09 13:41 by nicye      
@jeff377
我是拿 DetailsView 这个控件说的
我用它来做添加/修改功能的确是加个 InsertParamter 和添加一个 <%# Bind 就可以了
不添加 Bind 也行,那需要在 Inserting/Updating 事件里设置它的值

#10楼    回复  引用  查看    

2008-06-10 10:47 by 要有好的心情      
"若异动字段非常多":
无论用什么方法,都要修改数据访问层 、Model和 表示层。你有其他万能方法吗?即使有ORM,你还不是也要修改映射文件、表示层。

“当你的系统非常庞大时,例如有上千个窗体,当这些窗体若需同时新增一个字段时.....”:说明表示层你没有使用用户控件。

“批次异动问题”:个人感觉批量更新,在web程序中的使用问题有待商量,既然已经提交到wen服务器了,也不差再多访问数据库服务器一下了,毕竟web程序中最耗时的是,网络trip,相比处理时间而言。 批量更新更适用于WinForm程序。

强类型DataSet的问题:个人感觉比弱类型好。

#11楼    回复  引用    

2008-06-10 14:03 by 体彩 [未注册用户]
受益颇深,转走了哈!!!

#12楼 [楼主]   回复  引用  查看    

2008-06-10 15:30 by jeff377      
@要有好的心情
新增一个字段(字段)是否要同步更新中间层,这个要看你的中间层怎么写,我开发的系统所有的字段都是用定义出来的,也就是开发人员不用直接去下 SQL 语法,这种情形下就算增减字段,中间层是无预做任何异动。

批次异动的问题,在一般的 Web 系统比较不会发生,不过若是开发 Web ERP,那批次异动的需求就很大。就像你说的,这种批次异动比较适合使用 WinForm,这点我当然也了解,不过客户的需求就是要硬要使用 WebForm 而不用 WinForm 的 ERP 系统,那就没辨法了。

#13楼    回复  引用  查看    

2008-06-12 16:15 by 要有好的心情      
确实中间层的可以用数据库的架构信息来同步,不知道你有没有Model 类,有的话,如何同步数据库架构信息,有映射文件吗?
一般来说,我如果在程序中是使用了SQL或动态生成了SQL,基于一个业务对象都会写一次(除非特殊情况),这样修改时,一般就修改这一个地方,对于所有业务对象都要加减某字段,由基类控制。

关于批量更新的问题:
客户要求批量更新,这是需求问题,而不是程序设计问题,既然客户这样要求肯定要这样做,另外使用ObjectDataSoruce作为代理来处理数据,并不一定让你将数据直接提交到DB,ObjectDataSoruce的UpdateMethod、InsertMethod、DeleteMethod所关联的业务逻辑层方法,没有确定一定要操作数据库,你也可以仅处理强类型集合,不过这些数据要缓存一下,表示层提供集中提交的入口,需要集中提交时,从缓存中获取数据,一次性提交所有变更,这个DataSet本身已提供。

#14楼 [楼主]   回复  引用  查看    

2008-06-12 17:58 by jeff377      
@要有好的心情
针对批量更新的问题,如同你说的一样,我设计的TBObjectDataSoruce 控件的 UpdateMethod、InsertMethod、DeleteMethod
就是直接存取 TBBusinessObject 控件,并不是直接呼叫中间层去异动数据库。