DevExpress eXpressApp框架(XAF)和eXpress持久对象(XPO):如何加快关联的加载时间?
我在访问具有大量记录的关联属性的速度方面遇到问题。
我有一个XAF应用,其父类名为" MyParent"。
MyParent中有230条记录。
MyParent有一个名为MyChild的子类。
MyChild中有49,000条记录。
我以标准方式在MyParent
和MyChild
之间定义了一个关联:
在MyChild
中:
// MyChild (many) and MyParent (one) [Association("MyChild-MyParent")] public MyParent MyParent;
在MyParent中:
[Association("MyChild-MyParent", typeof(MyChild))] public XPCollection<MyCHild> MyCHildren { get { return GetCollection<MyCHild>("MyCHildren"); } }
有一个名为" MyParent1"的特定" MyParent"记录。
对于" MyParent1",有630个" MyChild"记录。
我有一个名为MyUI
的类的DetailView。
用户在MyUI DetailView的一个下拉列表中选择一个项目,而我的代码必须用MyChild对象填充另一个下拉列表。
用户在第一个下拉菜单中选择" MyParent1"。
我在MyUI中创建了一个属性,以在第一个下拉列表中为所选值返回MyChild对象的集合。
这是该属性的代码:
[NonPersistent] public XPCollection<MyChild> DisplayedValues { get { Session theSession; MyParent theParentValue; XPCollection<MyCHild> theChildren; theParentValue = this.DropDownOne; // get the parent value if theValue == null) { // if none return null; // return null } theChildren = theParentValue.MyChildren; // get the child values for the parent return theChildren; // return it }
我将DisplayedValues属性标记为NonPersistent,因为仅DetailVIew的UI才需要它。我认为持久化它不会在第一时间加快集合的创建,并且在用于填充下拉列表之后,我不需要它,因此我不想花时间存储它。
问题是调用theParentValue = this.DropDownOne
需要45秒。
眼镜:
- Vista商业
- 8 GB的RAM
- 2.33 GHz E6550处理器
- SQL Server Express 2005
对于用户来说,这太长了,无法等待DetailView中的多个下拉菜单之一。
我花了一些时间来草拟业务案例,因为我有两个问题:
- 如何使关联的值加载更快?
- 是否有另一种(简单)的方式来对下拉菜单和DetailView进行编程以使其运行得更快?
是的,我们可以说630项太多,无法在下拉菜单中显示,但是这段代码花费的时间太长,我怀疑速度与49,000而不是630成比例。对于我的应用而言,数量不多。
我的应用程序中需要使用这些下拉菜单中的许多下拉列表,因此强制用户为每个表单输入更复杂的过滤条件是不合适的。用户需要选择一个值并查看相关值。
我会知道查找大量记录的速度是否很慢,但是查找几百条记录不应该花那么长时间。
解决方案
回答
首先,我们应该对此操作应该花费这么长时间持怀疑态度,对读操作而言,XPO只会增加30%到70%的开销,而在这样的少量数据上,我们应该说的是毫秒而不是秒。
一些通用的性能提示可在DevExpress论坛上找到,并以对象缓存,延迟与深度加载等为中心,但我认为在情况下,这是另外一回事,不幸的是,很难再次猜测问题的根源,仅比方说,它不太可能是XPO的问题,更可能是其他问题,我倾向于查看会话创建(这也会创建对象缓存)和SQL连接代码(IDataStore的东西),如果无法彻底解决主机问题,并且我们没有建立池/重新使用连接,通常会很慢,此问题可能会加剧。
回答
感谢回答。正如我们所建议的,我创建了一个单独的解决方案,并能够获得良好的性能。
我的SQL连接正常,可以与应用程序中的其他功能一起使用。
鉴于我正在使用XAF并且没有做任何多余的事情,我的会话不是由XAF管理吗?
我使用的会话是从DetailView中读取的。
回答
我不确定为什么会按原样进行。如果我们创建了这样的关联:
public class A : XPObject { [Association("a<b", typeof(b))] public XPCollection<b> bs { get { GetCollection("bs"); } } } public class B : XPObject { [Association("a<b") Persistent("Aid")] public A a { get; set; } }
然后在我们要填充下拉列表时(例如lookupEdit控件)
A myA = GetSomeParticularA(); lupAsBs.Properties.DataSource = myA.Bs; lupAsBs.Properties.DisplayMember = "WhateverPropertyName";
我们不必加载A的孩子,XPO会在需要时加载它们,并且根本不需要会话管理。
回答
我不确定情况,只想分享一些我在XAF方面的经验。
第一次单击下拉列表(查找列表)控件(在详细视图中)时,将有两个查询发送到数据库以填充列表。在我的测试中,有时将整个对象加载到源集合中,而不仅仅是ID和Name属性,这取决于我们认为取决于对象的列表,我们可能希望使用较浅的对象。我们也可以打开列表的"服务器模式",则每次仅加载128个对象。