性能是很重要的一个质量属性,架构中都会考虑性能,目前OpenExpressApp主要实现了对象懒加载、传输压缩等一些性能优化,后续还需要不断完善和改进。本篇主要讲一下目前与性能相关的一些问题,由于框架是面向对象的,所以会有一些使用面向对象的一些特定的方面,也欢迎大家多提问题和方案。
已实现
WCF传输压缩
传输优化是网络产品考虑性能的主要点之一,OpenExpressApp使用了WCF的一个压缩通道,基于CSLA开发,压缩率可以达到20倍,源码在 【OpenSource】目录下的CompactMessageEncoder_src.zip,参考文档在CompactMessageEncoder
根对象懒加载-单据模块懒加载列表记录
根对象如果是单据样式模 块,根对象需要实现【MergeOldObject】把点击列表后取得的对象合并到列表对象中,实现单据模块懒加载对象功能。在 OpenExpressApp.Module.WPF项目的单据模块模板控制器ListDetailFormController.cs代码中,当点击列 表获取记录后会把获取的对象同步到列表中。
: base(windowTemplate)
{
detailViewController = new DetailViewController(View.DetailView, new EventHandler(DetaiDataChanged));
...
}
void DetaiDataChanged( object sender, EventArgs e)
{
// 由于异步获取DetailData,所以此时的CurrentObject不一定是dataprovider获取时的那个对象了
// 添加lock,防止异步操作时DataGrid出现UI问题
lock (thisLock)
{
BusinessBase o = (sender as GCslaDataProvider).Data as BusinessBase;
if ( null == o) return ;
BusinessBase _detailItem = null ;
foreach (BusinessBase item in (View.Data as IList))
{
if (item.GetPropertyValue( " Id " ).Equals(o.GetPropertyValue( " Id " )))
{
_detailItem = item;
break ;
}
}
_detailItem.MergeOldObject(o);
_detailItem.BeginEdit();
View.CurrentObject = _detailItem; // 必须设置CurrentObject,否则可能会导致列表的CurrentObject和DetailView的CurrentObject不一致
}
}
复杂子对象属性懒加载
如果一个对象的子对象比较大的时候,可以懒加载这个子对象列表属性,代码如下:
RegisterProperty(new PropertyInfo<ContractBudgets>("ContractBudgets"));
[Association]
public ContractBudgets ContractBudgets
{
get
{
if (!FieldManager.FieldExists(ContractBudgetsProperty))
{
if (IsNew)
LoadProperty(ContractBudgetsProperty, ContractBudgets.NewChild());
else
LoadProperty(ContractBudgetsProperty, ContractBudgets.Get(this));
}
return GetProperty(ContractBudgetsProperty);
}
}
UI层支持子对象属性懒加载方式为:给业务根对象赋值时,把子对象清空,当选择子对象对于的Tab页签时再绑定属性值到Data中
/// CurrentObjectChanged事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void OnCurrentObjectChanged( object sender, EventArgs e)
{
SetChildData();
if (CurrentObjectChanged != null )
{
CurrentObjectChanged(sender, e);
}
}
/// <summary>
/// 绑定这个视图的子视图
///
/// 把CurrentObject中对应每个子视图的属性,取值出来,并赋值给子视图
/// </summary>
/// <param name="view"></param>
private void SetChildData()
{
if ( null == this .CurrentObject)
{
foreach (var child in this .ChildViews)
{
child.Data = null ;
}
}
else
{
foreach (var child in this .ChildViews)
{
// 把CurrentObject中对应每个子视图的属性,取值出来,并赋值给子视图
// child.Data = (this.CurrentObject as BusinessBase).GetPropertyValue(child.PropertyName);
// 考虑细表大采用懒加载属性时,这里只清空细表,在TabItem可见时更新当前ChildView.Data,以免一次全部装载所有细表
child.Data = null ;
}
}
}
CSLA差异保存
CSLA目前通用做法是整个对象在网络上传输,客户端更新时不管是更新了多少内容,它会把整个对象返回到服务器端。如果这个对象有几千条记录,而只更新了一两条记录,那么回传整个对象无疑是一个很大的浪费。在业务逻辑不需要整个对象的情况下,我们可以做增量更新,只回传增加、更新或删除的数据到服务器端。
信息系统开发平台OpenExpressApp - 支持差异更新
CSLA保存后不回传对象
CSLA目前对象保存时会从服务器端传回一个对象,如果更新后回传的对象和本地的完全一样,则我们可以不必要回传这个对象,通过差异保存的Command实现此功能,回传会来的只是更新的对象
查询对象懒加载
查询模块支持同一查询对象查询多个对象,OEA总是先加载当前页签的查询对象,切换到相应页签时才获取这个页签对应的查询对象的数据,避免了一次性获取所有对象。
待实现
业务对象的引用对象缓存
业务对象的引用对象很多都是类似字典类可以缓存的数据,现在这类数据在每个业务对象获取数据时也是从数据库获取,并且保留在对象中一并传到客户端,这样与数据库交互以及网络传输量都增大了,后续遇到这类性能问题时将着重解决
服务器对象缓存
业务对象缓存,减少与数据库服务器的交互次数
客户端对象缓存
C/S结构时,可以把业务对象缓存到客户端本地来减少网络交互次数