DevExpress_XAF_根据集合(Collection)计算属性值(例子:产品列表统计订单明细)

  事先声明,本文大部分内容根据官方文件得到,有些翻译不准确的还望见谅。

  什么叫基于集合计算属性值?根据下图我们可以知道。在订单关系中,订单数量(Orders Count)、订单金额总计(Orders Total)、订单最大值 (Maximum Order),由下方列表(在业务类中用集合表示)经过统计获得。

初始化类的实现(没有统计功能时的源码)

  订单(Order)和产品(Product)关系为多对多。

  产品(Product)源码:

 1 [DefaultClassOptions]
 2 public class Product : BaseObject {
 3     public Product(Session session) : base(session) { }
 4     private string fName;
 5     public string Name {
 6         get { return fName; }
 7         set { SetPropertyValue("Name", ref fName, value); }
 8     }
 9     [Association("Product-Orders"), Aggregated]
10     public XPCollection<Order> Orders {
11         get { return GetCollection<Order>("Orders"); }
12     }
13 }

   订单源码:

 1 [DefaultClassOptions]
 2 public class Order : BaseObject {
 3     public Order(Session session) : base(session) { }
 4     private string fDescription;
 5     public string Description {
 6          get { return fDescription; }
 7          set { SetPropertyValue("Description", ref fDescription, value); }
 8     }
 9     private decimal fTotal;
10     public decimal Total {
11         get { return fTotal; }
12         set { SetPropertyValue("Total", ref fTotal, value); }
13     }
14     private Product fProduct;
15     [Association("Product-Orders")]
16     public Product Product {
17         get { return fProduct; }
18         set { SetPropertyValue("Product", ref fProduct, value); }
19     }
20 }

计算属性

  下面的代码片段演示了三个计算属性的实现——订单数量(Orders Count)、订单金额总计(Orders Total)、订单最大值 (Maximum Order)

 1 [DefaultClassOptions]
 2 public class Product : BaseObject {
 3     // ... 
 4     private int? fOrdersCount = null;
 5     public int? OrdersCount {
 6         get {
 7             if(!IsLoading && !IsSaving && fOrdersCount == null)
 8                 UpdateOrdersCount(false);
 9             return fOrdersCount;
10         }
11     }
12     private decimal? fOrdersTotal = null;
13     public decimal? OrdersTotal {
14         get {
15            if(!IsLoading && !IsSaving && fOrdersTotal == null)
16                 UpdateOrdersTotal(false);
17             return fOrdersTotal;
18         }
19     }
20     private decimal? fMaximumOrder = null;
21     public decimal? MaximumOrder {
22         get {
23             if(!IsLoading && !IsSaving && fMaximumOrder == null)
24                 UpdateMaximumOrder(false);
25             return fMaximumOrder;
26         }
27     }
28 }

   以下方法是三个计算属性值具体方法。

 1 [DefaultClassOptions]
 2 public class Product : BaseObject {
 3     // ... 
 4     public void UpdateOrdersCount(bool forceChangeEvents) {
 5         int? oldOrdersCount = fOrdersCount;
 6         fOrdersCount = Convert.ToInt32(Evaluate(CriteriaOperator.Parse("Orders.Count")));
 7         if (forceChangeEvents)
 8           OnChanged("OrdersCount", oldOrdersCount, fOrdersCount);
 9     }
10     public void UpdateOrdersTotal(bool forceChangeEvents) {
11         decimal? oldOrdersTotal = fOrdersTotal;
12         decimal tempTotal = 0m;
13         foreach (Order detail in Orders)
14             tempTotal += detail.Total;
15         fOrdersTotal = tempTotal;
16         if (forceChangeEvents)
17             OnChanged("OrdersTotal", oldOrdersTotal, fOrdersTotal);
18     }
19     public void UpdateMaximumOrder(bool forceChangeEvents) {
20         decimal? oldMaximumOrder = fMaximumOrder;
21         decimal tempMaximum = 0m;
22         foreach (Order detail in Orders)
23             if (detail.Total > tempMaximum)
24                 tempMaximum = detail.Total;
25         fMaximumOrder = tempMaximum;
26         if (forceChangeEvents)
27             OnChanged("MaximumOrder", oldMaximumOrder, fMaximumOrder);
28     }
29 }

   注意,fOrdersCount是在客户端使用UpdateOrdersCount方法中从内部XPO缓存加载的对象来计算的。可以使用下面的代码在服务器端计算fOrdersCount,这样就不会考虑未提交的对象。

1 fOrdersCount = Convert.ToInt32(Session.Evaluate<Product>(CriteriaOperator.Parse("Orders.Count"), 
2     CriteriaOperator.Parse("Oid=?", Oid)));

  在Order类的TotalProduct属性设置器中,当Order对象的属性值发生变化且对象当前没有初始化时,UI将被更新:

 1 [DefaultClassOptions]
 2 public class Order : BaseObject {
 3     // ... 
 4     private decimal fTotal;
 5     public decimal Total {
 6         get { return fTotal; }
 7         set {
 8             bool modified = SetPropertyValue("Total", ref fTotal, value);
 9             if(!IsLoading && !IsSaving && Product != null && modified) {
10                 Product.UpdateOrdersTotal(true);
11                 Product.UpdateMaximumOrder(true);
12             }
13         }
14     }
15     private Product fProduct;
16     [Association("Product-Orders")]
17     public Product Product {
18         get { return fProduct; }
19         set {
20             Product oldProduct = fProduct;
21             bool modified = SetPropertyValue("Product", ref fProduct, value);
22             if(!IsLoading && !IsSaving && oldProduct != fProduct && modified) {
23                 oldProduct = oldProduct ?? fProduct;
24                 oldProduct.UpdateOrdersCount(true);
25                 oldProduct.UpdateOrdersTotal(true);
26                 oldProduct.UpdateMaximumOrder(true);
27             }
28         }
29     }
30 }

   在Product类中,OnLoaded方法被覆盖,因为在使用延迟计算时需要重置缓存的值。

 1 [DefaultClassOptions]
 2 public class Product : BaseObject {
 3     // ... 
 4     protected override void OnLoaded() {
 5         Reset();
 6         base.OnLoaded();
 7     }
 8     private void Reset() {
 9         fOrdersCount = null;
10         fOrdersTotal = null;
11         fMaximumOrder = null;
12     }
13     // ...

 将计算的值属性存储到数据库中

非持久性属性值时影响性能的。为了避免这个问题,可以将计算值存储到数据库中。可以使用PersistentAttribute将值保存到数据库中。

 1 [DefaultClassOptions]
 2 public class Product : BaseObject {
 3     // ... 
 4     [Persistent("OrdersCount")]
 5     private int? fOrdersCount = null;
 6     [PersistentAlias("fOrdersCount")]
 7     public int? OrdersCount {
 8         // ... 
 9     }
10     [Persistent("OrdersTotal")]
11     private decimal? fOrdersTotal = null;
12     [PersistentAlias("fOrdersTotal")]
13     public decimal? OrdersTotal {
14         // ... 
15     }
16     [Persistent("MaximumOrder")]
17     private decimal? fMaximumOrder = null;
18     [PersistentAlias("fMaximumOrder")]
19     public decimal? MaximumOrder {
20         // ... 
21     }
22     // ...

 从主订单类中移除OnLoaded方法重载。

参考文献

  [1] https://documentation.devexpress.com/eXpressAppFramework/113179/Task-Based-Help/Business-Model-Design/eXpress-Persistent-Objects-XPO/How-to-Calculate-a-Property-Value-Based-on-Values-from-a-Detail-Collection

  [2]官网项目源码及示例网址:https://www.devexpress.com/Support/Center/Example/Details/E305/how-to-calculate-a-master-property-based-on-values-from-a-details-collection

posted @ 2019-09-06 15:44  陆陆无为而治者  阅读(412)  评论(0编辑  收藏  举报