放弃业务对象中的更改






4.67/5 (25投票s)
2006年11月16日
3分钟阅读

97731

994
如何构建一个具有放弃更改选项的业务对象。
必备组件
为了运行示例并阅读本文,您必须安装 Visual Studio 2005 和 C#。
引言
处理数据的最方便和高级的方法是使用封装业务逻辑的业务对象。然后,这些对象调用数据访问层来持久化信息。业务对象可以手动创建或由 ORM 工具生成。
一旦我们准备好类并将其填充(从持久层提取数据),我们会在一些网格中显示对象,并允许用户在表单中编辑对象。到目前为止一切顺利。感谢微软提供的 Binding
类以及设置绑定后让 .NET Framework 管理表单控件和业务对象之间数据交换的能力。
问题
作为一个典型案例,用户从网格中选择一个对象并打开编辑表单。显示模式表单,并且业务对象的属性绑定到表单控件。通过使用数据绑定,我们可以根据 DataSourceUpdateMode
枚举将控件中更改的数据提交到对象
Never
- 从不更新数据源,并且输入到控件中的值不会被解析、验证或重新格式化。OnPropertyChanged
- (default
) 只要控件属性的值发生变化,就会更新数据源。OnValidation
- 只要控件属性被验证,就会更新数据源。
这给了我们一些控制“何时”更新数据源的权限。如果我们想放弃更改怎么办?
解决方案
此时,我们有两种解决方案
Validate()
方法第一种不是非常优雅,但更明显 - 我们可以使用
DataSourceUpdateMode.OnValidation
模式来更新数据源,并且仅当用户想要确认数据时才调用Form.Validate()
方法。如果要放弃数据,则不调用Validate()
方法。这会引入一致性问题:如果某些控件被验证(并且源已更新)而其余的未被验证,该怎么办?当然,我们会要求用户修复输入的信息。但如果此时,用户决定取消对象编辑,我们就陷入困境,因为某些字段已经更新。IEditableObject
接口幸运的是,可以使用 .NET 工具来实现这一点。这就是
IEditableObject
接口。此接口声明了三个公共方法BeginEdit()
- 开始对对象进行编辑。CancelEdit()
- 放弃自上次BeginEdit
调用以来的更改。EndEdit()
- 将自上次BeginEdit
或IBindingList.AddNew
调用以来的更改推送到底层对象。
还有另一个好消息 - 微软控件支持并与此接口配合良好。我们所要做的就是在我们的业务对象中实现此接口。这需要我们做一些工作,但给了我们足够的灵活性。我个人更喜欢创建一个实现公共逻辑(包括
IEditableObject
方法)的所有业务对象的基类。
通用 IEditableObject 实现
这里提供了一个通用实现,可以轻松添加到基类并包含在现有项目中。此实现保留了所有公共属性的值,不关注所有字段、私有属性、没有 set 访问器的公共属性
首先,我们需要一些 key
/value
对集合,它将为我们保存原始值。
存储原始值
这也是对象处于编辑模式的标志。
Hashtable props = null;
BeginEdit()
此方法使用反射存储当前值以供将来恢复。
public void BeginEdit()
{
//exit if in Edit mode
//uncomment if CancelEdit discards changes since the
//LAST BeginEdit call is desired action
//otherwise CancelEdit discards changes since the
//FIRST BeginEdit call is desired action
//if (null != props) return;
//enumerate properties
PropertyInfo[] properties = (this.GetType()).GetProperties
(BindingFlags.Public | BindingFlags.Instance);
props = new Hashtable(properties.Length - 1);
for (int i = 0; i < properties.Length; i++)
{
//check if there is set accessor
if (null != properties[i].GetSetMethod())
{
object value = properties[i].GetValue(this, null);
props.Add(properties[i].Name, value);
}
}
}
CancelEdit()
此方法恢复旧值。
public void CancelEdit()
{
//check for inappropriate call sequence
if (null == props) return;
//restore old values
PropertyInfo[] properties =(this.GetType()).GetProperties
(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < properties.Length; i++)
{
//check if there is set accessor
if (null != properties[i].GetSetMethod())
{
object value = props[properties[i].Name];
properties[i].SetValue(this, value, null);
}
}
//delete current values
props = null;
}
EndEdit()
此方法仅删除存储的值(以及我们的标志)。
public void EndEdit()
{
//delete current values
props = null;
}