自定义可绑定数据的业务对象实体和强类型-Part Five

对数据库做增,删,改操作

至今,我们已经添加代码,从数据层(DataLayer)绑定数据到表现层中的数据绑定控件(DataGridView).这里,用户可以添加,删除或者修改Customer或者Order相关数据,通过DataGridView提供的界面接口.经过添加,删除或者修改数据后,用户可以选择更新输入的信息到数据库中.在本篇剩下的部分,我们将描述有关的必要的步骤,怎么用新的,修改的或者删除的数据区更新数据库.

这里缺少一些相关的代码,来更新我们的Customer对象到数据层(DataLayer),首先,我们将添加两个List实例,做为我们Customer管理窗体的私有成员.这些List实例将保持明确删除的Customers和Orders.

 

private List<CustomerBO> m_deletedCustomers = null

private List<OrderBO> m_deletedOrders = null

 

下一步,我们应该处理customerBOBindingSource的AddingNew事件,为BindingSource处理一个新的Customer对象的添加(如图19).

clip_image002 
图19.处理CustomerBindingSource的AddingNew事件

处理添加一个新Customer到我们的CustomerBindingSource的代码,如下所示.

private void customerBOBindingSource_AddingNew(object sender, AddingNewEventArgs e) 

    CustomerBO customer 
= new CustomerBO(); 
    customer.IsNew 
= true
    customer.IsDirty 
= true

    customer.CompanyName 
= "[新客户名]"
    customer.CustomerId 
= "[新客户ID]"

    e.NewObject 
= customer; 
    customer 
= null
}
 

相同的事件处理过程应该被激活,为我们的OrderBindingSource.注意(看下面的代码)到,用于添加一个新订单的代码,也应该用一个到父集合(Customer)的引用.因为我们的订单对象必须有个唯一的OrderID,我将设置该ID为一个负自增值.我们的"Orders"数据集DataSet包含一个OrderID列,该列设置为一个自增列;Order对象中的ID属性设置为一个负值,是为了避免在将一个新的Order行插入到数据库中时,发生冲突.在服务器端,当在Order表中插入一个新行时,数据库服务器将添加一个新的OrderID值,并且,一个新的唯一OrderID值将在更新的DataSet中返回,而且,应该与客户端的对象的值保持同步(我将在本文档的下个小结中解释该特性).

private void ordersBindingSource_AddingNew(object sender, AddingNewEventArgs e) 

    OrderBO order 
= new OrderBO(); 
    order.IsNew 
= true
    order.IsDirty 
= true
    order.OrderDate 
= DateTime.Today; 
    order.ProductName 
= "[新产品名]"

    
//--- Set Temporary OrderID - Will be set to negative 
    
//value to avoid update conflicts 
    m_lastOrderID--
    order.OrderId 
= m_lastOrderID; 

    
//--- Get the Current Customer 
    CustomerBO currentCustomer = (CustomerBO) customerBOBindingSource.Current; 

    
if (!(currentCustomer == null)) 
    

        order.Customer 
= currentCustomer; 
    }
 
    
else 
    

        
throw new NullReferenceException("订单的客户找不到!"); 
    }
 
    e.NewObject 
= order; 
    order 
= null
}

处理改进的事件对于表现层的开发人员来说非常显然.这里没有什么专门处理CustomerBO或者OrderBO的属性修改部分的类.我们将逐步地讨论这些类.这些辅助类部署在解决方案的业务层集合中.

让我们以IEventPublisher接口开始介绍,该接口有一套对象属性修改事件的蓝图.让我们进一步考察这个接口类:

public interface IEventPublisher
{
    
void RegisterListener<T>(T p_listener) where T : IEventListener;
    
void UnregisterListener<T>(T p_listener) where T : IEventListener;
    
void NotifyListeners();
    
bool IsDirty getset;}
    
bool Initializing getset;}
    
bool IsNew getset;}
}

该IEventPublisher接口有为监听对象注册和反注册所用的方法接口,当一个对象属性值改变时,通知监听者,还有2个属性设置,IsDirty属性用来将一个附加对象标识为修改的状态,另外,当加载对象数据时,Initializing属性设置为true(因此要预防加载对象中的数据过程中,启动该修改事件).

下一步,我们看看IEventListener接口.该接口含有一个到Publisher对象的引用(我们的概念中,指customer或者order对象),并且描述了一个方法的签名,该方法专门用来处理对象属性"修改"事件.

 

public interface IEventListener
{
    
void OnNotification(IEventPublisher p_publisher);
}

Publisher类是每个自定义对象业务类的基础类.业务对象直接继承该Publisher类.该Publisher类含有"注册"和"反注册"监听对象的方法.监听对象就是指那些需要在业务对象类别的属性修改时,被通知的对象.一个典型的监听者是一个Windows Form.该基类也包含一些基础的属性,用来设置业务对象到一些初始状态,如"IsNew","IsDirty"(修改过的),"IsInitializing"状态.

public abstract class Publisher : IEventPublisher
{
    
private delegate void m_eventHandler(IEventPublisher p_publisher);
    
private event m_eventHandler m_event;

    
IEventPublisher 成员
}

ObjectChangedListener类包含了OnNotification方法,当业务对象类(是注册到NotifyChanged事件中的)属性值发生改变时,执行该方法;

public class ObjectChangedListener : IEventListener
{
    
IEventListener 成员
}

因此(看下面的代码),Notification事件被附加到set属性中.所以,当一个属性值变化时,该事件将抛出(CustomerBO的属性).

public string CustomerId 

    
get return m_CustomerId; } 
    
set 
    

        m_CustomerId 
= value; 
        NotifyListeners(); 
    }
 
}
 

public string CompanyName 

    
get return m_CompanyName; } 
    
set 
    

        m_CompanyName 
= value; 
        NotifyListeners(); 
    }
 
}
 

当使用者单击保存按钮,下一步,代码将被执行,用新增的,修改的或者删除的对象,回写更新数据库.因为这里有很多相关的代码,我将在代码内部进行说明.

private void customerBOBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
    
//--- Validate the Value which loses control first
    this.Validate();

    
//--- End the CurrentEdit on the BindingSources
    customerBOBindingSource.EndEdit();
    ordersBindingSource.EndEdit();

    
//--- Create Customer and Order List to hold the 
    
//Changed objects
    List<CustomerBO> changedCustomers = null;
    List
<OrderBO> changedOrders = null;

    
//--- Loop through the ObjectStacks to catch changed 
    
//property data
    foreach (Object obj in customerBOBindingSource)
    
{
        CustomerBO customer 
= (CustomerBO) obj;
        
if (customer.IsDirty)
        
{
            
if (changedCustomers == null)
                changedCustomers 
= new List<CustomerBO>();
            changedCustomers.Add(customer);
        }

        
foreach (OrderBO order in customer.Orders)
        
{
            
if (order.IsDirty)
            
{
                
if (changedOrders == null)
                    changedOrders 
= new List<OrderBO>();
                changedOrders.Add(order);
            }

        }

        customer 
= null;
    }


    
if (changedCustomers != null || changedOrders != null || m_deletedCustomers != null || m_deletedOrders != null)
    
{
        
bool IsUpdateOK = true;

        
try
        
{
            
//--- Update through Business Object Layer
            int numUpdate = m_customerBO.SaveCustomerOrders(changedCustomers,
                                                            m_deletedCustomers, 
                                                            changedOrders,
                                                            m_deletedOrders);

            
//--- Display Success
            MessageBox.Show(String.Format("{0}行成功更新到数据库!", numUpdate.ToString()));
        }

        
catch (Exception ex)
        
{
            IsUpdateOK 
= false;
            
//--- Show Error
            MessageBox.Show(ex.Message, "发生错误,更新失败!");
        }

        
finally
        
{
            
//--- Reset object state & Release Resources
            if (IsUpdateOK)
            
{
                
//--- First Syncronize the OrderID's with 
                
//Server Versions
                if (changedOrders != null)
                
{
                    m_customerBO.SyncroOrderID(changedOrders);
                }


                
if (changedCustomers != null)
                
{
                    
foreach (CustomerBO customer in changedCustomers)
                    
{
                        customer.IsDirty 
= false;
                        customer.IsNew 
= false;
                    }

                    changedCustomers 
= null;
                }


                
if (changedOrders != null)
                
{
                    
foreach (OrderBO order in changedOrders)
                    
{
                        order.IsDirty 
= false;
                        order.IsNew 
= false;
                    }

                    changedOrders 
= null;
                }


                
//--- Release Helper Objects
                m_deletedCustomers = null;
                m_deletedOrders 
= null;

                
//--- Refresh the OrderGrid
                ordersDataGridView.Refresh();
            }

        }

    }

}

添加的和修改的对象可以在包含列表中被跟踪,删除的不能.因此,我们必须手动跟踪这些对象.所以,我们下一步必须在代码中部署下一个事件处理程序.

在定义部分:

public partial class CustomerAdmin : Form 

    
private CustomerBO m_customerBO; 
    
private List<CustomerBO> m_deletedCustomers = null
    
private List<OrderBO> m_deletedOrders = null
    …  
}
 

处理删除Customer或者Order对象的代码:

private void customerBODataGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
    
if (m_deletedCustomers == null)
        m_deletedCustomers 
= new List<CustomerBO>();

    m_deletedCustomers.Add((CustomerBO)e.Row.DataBoundItem);

    
if (((CustomerBO)e.Row.DataBoundItem).Orders != null)
    
{
        
if (m_deletedOrders == null)
            m_deletedOrders 
= new List<OrderBO>();

        m_deletedOrders.AddRange(((CustomerBO) e.Row.DataBoundItem).Orders);
    }

}


private void ordersDataGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
    
if (m_deletedOrders == null)
        m_deletedOrders 
= new List<OrderBO>();

    m_deletedOrders.Add((OrderBO)e.Row.DataBoundItem);
}

最后,我们的BusinessLayer Class解决处理到DAL的更新.如下所示的实现方法,还用了Optimistic的途径处理了DbConcurrency问题.

 

public int SaveCustomerOrders(List<CustomerBO> p_addedOrModifiedCustomers,
            List
<CustomerBO> p_deletedCustomers,
            List
<OrderBO> p_addedOrModifiedOrders,
            List
<OrderBO> p_deletedOrders)
        
{
            
//--- Create the Service to update the Data
            CustomerOrderService dataService = new CustomerOrderService();

            
Step 1 : Add Deleted Customer Object Information

            
Step 2 : Add Deleted Order Object Information

            
Step 3 : Add New/Modified Customer Object Information

            
Step 4 : Add New/Modified Order Object Information

            
Update through the DataService class

            
return 0;
        }

瞧… 都讲完了! 希望你喜欢这篇文章.

posted @ 2008-01-28 20:17 mickeysuda 阅读(...) 评论(...) 编辑 收藏