This topic describes how to implement a business class, so that one of its properties is calculated based on a property(ies) of the objects contained in the child object collection.

本主题介绍如何实现 Business 类,以便基于子对象集合中包含的对象的属性计算其属性之一。

Tip 提示
A complete sample project is available in the DevExpress Code Examples database at http://www.devexpress.com/example=E305
完整的示例项目可在 DevExpress 代码示例数据库中找到,http://www.devexpress.com/example=E305

.

Initial Class Implementation

A Product class has a collection of Order objects. The Product and Order classes are associated by the One-to-Many relationship, which means that a Product object may be associated with several Order objects. The collection of Order objects is aggregated. Order objects are created, belonging to one of the Product objects. When the master object is removed, all the objects in its aggregated collection are removed as well.

The following snippet illustrates the Product class implementation.

初始类实现

产品类具有 Order 对象的集合。产品和订单类由"一对多"关系关联,这意味着产品对象可能与多个 Order 对象关联。将聚合 Order 对象的集合。将创建属于"产品"对象之一的顺序对象。删除主对象时,其聚合集合中的所有对象也都将被删除。

以下代码段演示了产品类实现。

[DefaultClassOptions]
public class Product : BaseObject {
public Product(Session session) : base(session) { }
private string fName;
public string Name {
get { return fName; }
set { SetPropertyValue(nameof(Name), ref fName, value); }
}
[Association("Product-Orders"), Aggregated]
public XPCollection<Order> Orders {
get { return GetCollection<Order>(nameof(Orders)); }
}
}

The following snippet illustrates the Order class implementation.

以下代码段演示了 Order 类实现。

[DefaultClassOptions]
public class Order : BaseObject {
public Order(Session session) : base(session) { }
private string fDescription;
public string Description {
get { return fDescription; }
set { SetPropertyValue(nameof(Description), ref fDescription, value); }
}
private decimal fTotal;
public decimal Total {
get { return fTotal; }
set { SetPropertyValue(nameof(Total), ref fTotal, value); }
}
private Product fProduct;
[Association("Product-Orders")]
public Product Product {
get { return fProduct; }
set { SetPropertyValue(nameof(Product), ref fProduct, value); }
}
}

In the code above, the Order class contains the Total property and the Product class has the MaximumOrder and OrdersTotal properties. These Product's properties are calculated based on Total properties of the aggregated Orders. The OrderCount property is also added to the Product class. This property exposes the number of aggregated Orders.

在上面的代码中,"订单"类包含"总计"属性,而"产品"类具有"最大订单"和"订单总计"属性。这些产品的属性基于聚合订单的总计属性计算。"OrderCount"属性也会添加到"产品"类中。此属性公开聚合订单的数量。

Note 注意
You can modify an object from the child collection in a separate Detail View and save it. In this scenario, the parent object may also be marked as modified in a separate object space. If the collection property is not decorated with the AggregatedAttribute, you need to refresh the parent object before saving changes. To avoid this, disable the XpoDefault.IsObjectModifiedOnNonPersistentPropertyChange option before starting the application.
您可以在单独的"详细视图"中修改子集合中的对象并保存它。在这种情况下,父对象也可以标记为在单独的对象空间中修改。如果集合属性未使用聚合属性进行修饰,则需要在保存更改之前刷新父对象。为了避免这种情况,在启动应用程序之前,请禁用 XpoDefault.IsObjectModifiedon 无持久性属性更改选项。

Implement Non-Persistent Calculated Properties

An implementation of "lazy" calculated (calculated on demand) properties is described in this section.

Omit the property setter to implement a non-persistent property. The following code snippet demonstrates the implementation of three calculated properties - the OrdersCount, OrdersTotal and MaximumOrder.

实现非持久计算属性

本节将介绍计算(按需计算)属性的"懒"属性的实现。

省略属性集器以实现非持久性属性。以下代码段演示了三个计算属性的实现 - 订单计数、订单总计和最大订单。

[DefaultClassOptions]
public class Product : BaseObject {
// ...
private int? fOrdersCount = null;
public int? OrdersCount {
get {
if(!IsLoading && !IsSaving && fOrdersCount == null)
UpdateOrdersCount(false);
return fOrdersCount;
}
}
private decimal? fOrdersTotal = null;
public decimal? OrdersTotal {
get {
if(!IsLoading && !IsSaving && fOrdersTotal == null)
UpdateOrdersTotal(false);
return fOrdersTotal;
}
}
private decimal? fMaximumOrder = null;
public decimal? MaximumOrder {
get {
if(!IsLoading && !IsSaving && fMaximumOrder == null)
UpdateMaximumOrder(false);
return fMaximumOrder;
}
}
}

The properties' business logic is contained into three separate methods - UpdateOrdersCount, UpdateOrdersTotal and UpdateMaximumOrder. These methods are invoked in the property getters. Having the business logic in separate methods allows you to update a property's value by calling the corresponding method, when required. The OrdersCount is a simple calculated non-persistent property. This property is calculated using XPO criteria language. The OrdersTotal and MaximumOrder are complex calculated non-persistent properties, not expressed using the criteria language. So, traverse the Orders collection to calculate these properties.

属性的业务逻辑包含在三个单独的方法中 - 更新订单计数、更新订单总计和更新最大订单。这些方法在属性 getter 中调用。将业务逻辑用到单独的方法中允许您在需要时通过调用相应的方法来更新属性的值。OrdersCount 是一个简单的计算非持久性属性。此属性是使用 XPO 条件语言计算的。订单总计和最大订单是复杂计算的非持久性属性,不是使用条件语言表示的。因此,遍历"订单"集合以计算这些属性。

Note 注意
In this topic, the OrdersTotal and MaximumOrder properties are considered to be complex to illustrate how such properties are calculated. Actually, their values can be easily calculated using XPO criteria language. For instance, you can use the Avg, Count, Exists, Max and Min functions to perform aggregate operations on collections. Refer to the Criteria Language Syntax topic for details.
在本主题中,"订单总计"和"最大订单"属性被视为复杂属性,以说明如何计算这些属性。实际上,可以使用 XPO 标准语言轻松计算其值。例如,您可以使用平均、计数、存在、最大值和最小值函数对集合执行聚合操作。有关详细信息,请参阅标准语言语法主题。

The following snippet illustrates the UpdateOrdersCount, UpdateOrdersTotal and UpdateMaximumOrder methods definitions.

以下代码段说明了更新订单计数、更新订单总计和更新最大订单方法定义。

[DefaultClassOptions]
public class Product : BaseObject {
// ...
public void UpdateOrdersCount(bool forceChangeEvents) {
int? oldOrdersCount = fOrdersCount;
fOrdersCount = Convert.ToInt32(Evaluate(CriteriaOperator.Parse("Orders.Count")));
if (forceChangeEvents)
OnChanged(nameof(OrdersCount), oldOrdersCount, fOrdersCount);
}
public void UpdateOrdersTotal(bool forceChangeEvents) {
decimal? oldOrdersTotal = fOrdersTotal;
decimal tempTotal = 0m;
foreach (Order detail in Orders)
tempTotal += detail.Total;
fOrdersTotal = tempTotal;
if (forceChangeEvents)
OnChanged(nameof(OrdersTotal), oldOrdersTotal, fOrdersTotal);
}
public void UpdateMaximumOrder(bool forceChangeEvents) {
decimal? oldMaximumOrder = fMaximumOrder;
decimal tempMaximum = 0m;
foreach (Order detail in Orders)
if (detail.Total > tempMaximum)
tempMaximum = detail.Total;
fMaximumOrder = tempMaximum;
if (forceChangeEvents)
OnChanged(nameof(MaximumOrder), oldMaximumOrder, fMaximumOrder);
}
}

Note that the fOrdersCount is evaluated on the client side using the objects loaded from an internal XPO cache in the UpdateOrdersCount method. You can use the following code to evaluate the fOrdersCount on the server side, so the uncommitted objects are not taken into account.

请注意,使用从 UpdateOrdersCount 方法中从内部 XPO 缓存加载的对象在客户端上计算 fOrdersCount。可以使用以下代码来评估服务器端的 fOrdersCount,因此不考虑未提交的对象。

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

In the Order class' Total and Product property setters, a UI is updated when an Order object's property values change and an object is not currently being initialized:

在 Order 类的"总计"和"产品"属性设置器中,当 Order 对象的属性值发生更改且对象当前未初始化时,将更新 UI:

[DefaultClassOptions]
public class Order : BaseObject {
// ...
private decimal fTotal;
public decimal Total {
get { return fTotal; }
set {
bool modified = SetPropertyValue(nameof(Total), ref fTotal, value);
if(!IsLoading && !IsSaving && Product != null && modified) {
Product.UpdateOrdersTotal(true);
Product.UpdateMaximumOrder(true);
}
}
}
private Product fProduct;
[Association("Product-Orders")]
public Product Product {
get { return fProduct; }
set {
Product oldProduct = fProduct;
bool modified = SetPropertyValue(nameof(Product), ref fProduct, value);
if(!IsLoading && !IsSaving && oldProduct != fProduct && modified) {
oldProduct = oldProduct ?? fProduct;
oldProduct.UpdateOrdersCount(true);
oldProduct.UpdateOrdersTotal(true);
oldProduct.UpdateMaximumOrder(true);
}
}
}
}

In the Product class, the OnLoaded method is overridden, as it is necessary to reset cached values when using "lazy" calculations.

在 Product 类中,将重写 OnLoaded 方法,因为使用 "懒"计算时必须重置缓存的值。

[DefaultClassOptions]
public class Product : BaseObject {
// ...
protected override void OnLoaded() {
Reset();
base.OnLoaded();
}
private void Reset() {
fOrdersCount = null;
fOrdersTotal = null;
fMaximumOrder = null;
}
// ...

Store Calculated Property Values in the Database

The non-persistent calculated properties can be inappropriate in certain scenarios, especially when a large number of objects should be manipulated. Each time such a property is accessed, a query to the database is generated to evaluate the property for each master object. For instance, suppose you have the Order business class which has the Total non-persistent property. This property is calculated from the properties of the objects contained in the Order's child object collection. To display an Order object in a List View, the Total property's value should be determined. To determine that value, a database query is generated. If the List View should display a thousand objects, a thousand queries will be generated. Obviously, this can have a negative impact on the performance of the application.

To avoid the performance issues, the calculated property values can be stored in the database. You can apply the PersistentAttribute to save values to the database (see How to: Use Read-Only Persistent Properties). Additionally, if it is assumed that the calculated property is to be used in a filter criterion or while sorting, the PersistentAliasAttribute can be applied.

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

在某些情况下,非持久性计算属性可能不合适,尤其是在应操作大量对象时。每次访问此类属性时,都会生成对数据库的查询,以评估每个主对象的属性。例如,假设您具有具有总计非持久性属性的 Order 业务类。此属性是根据 Order 的子对象集合中包含的对象的属性计算的。要在列表视图中显示 Order 对象,应确定 Total 属性的值。要确定该值,将生成数据库查询。如果列表视图应显示一千个对象,则将生成一千个查询。显然,这可能对应用程序的性能产生负面影响。

为了避免性能问题,计算的属性值可以存储在数据库中。您可以应用"持久属性"将值保存到数据库(请参阅:如何使用只读持久性属性)。此外,如果假定计算属性将在筛选条件中使用或在排序时使用,则可以应用"持久别名属性"。

[DefaultClassOptions]
public class Product : BaseObject {
// ...
[Persistent("OrdersCount")]
private int? fOrdersCount = null;
[PersistentAlias(nameof(fOrdersCount))]
public int? OrdersCount {
// ...
}
[Persistent("OrdersTotal")]
private decimal? fOrdersTotal = null;
[PersistentAlias(nameof(fOrdersTotal))]
public decimal? OrdersTotal {
// ...
}
[Persistent("MaximumOrder")]
private decimal? fMaximumOrder = null;
[PersistentAlias(nameof(fMaximumOrder))]
public decimal? MaximumOrder {
// ...
}
// ...

Remove the OnLoaded method overload from the master Order class.

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

How to: Calculate a Property Value Based on Values from a Detail Collection 如何:基于详细信息集合中的值计算属性值的更多相关文章

  1. How to: Initialize Business Objects with Default Property Values in XPO 如何:在 XPO 中用默认属性值初始化业务对象

    When designing business classes, a common task is to ensure that a newly created business object is ...

  2. How to: Initialize Business Objects with Default Property Values in Entity Framework 如何:在EF中用默认属性值初始化业务对象

    When designing business classes, a common task is to ensure that a newly created business object is ...

  3. Format a Property Value 设置属性值的格式

    In this lesson, you will learn how to set a display format and an edit mask to a business class prop ...

  4. <s:property="a" value=""/>取的<s:debug></s:debug>中的value stack中的属性值

    <s:property="a"  value=""/>取的<s:debug></s:debug>中的value stack中 ...

  5. Objective-C中变量采用@property的各个属性值的含义

    我们在OC中定义变量,可以自己来定义变量的setter方法来设置变量值,用getter方法来获取变量值.但是当变量数量增多时,还采用手动添加setter/getter方法来操作变量,就会使得程序代码量 ...

  6. 【跟着stackoverflow学Pandas】Select rows from a DataFrame based on values in a column -pandas 筛选

    最近做一个系列博客,跟着stackoverflow学Pandas. 以 pandas作为关键词,在stackoverflow中进行搜索,随后安照 votes 数目进行排序: https://stack ...

  7. Implement Property Value Validation in the Application Model 在应用程序模型中实现属性值验证

    In this lesson, you will learn how to check whether or not a property value satisfies a particular r ...

  8. Implement Property Value Validation in Code 在代码中实现属性值验证(XPO)

    This lesson explains how to set rules for business classes and their properties. These rules are val ...

  9. 跟踪对象属性值的修改, 设置断点(Break on property change)

    代码 //Break on property change (function () { var localValue; Object.defineProperty(targetObject, 'pr ...

随机推荐

  1. 阿里巴巴 Service Mesh 落地的架构与挑战

    点击下载<不一样的 双11 技术:阿里巴巴经济体云原生实践> 本文节选自<不一样的 双11 技术:阿里巴巴经济体云原生实践>一书,点击上方图片即可下载! 作者 | 方克明(溪翁 ...

  2. Reveal分析工具的使用

    首先:在reveal官网http://revealapp.com/下载适用版本.试用版本是30天免费,可以选择破解.破解链接http://pan.baidu.com/s/1bnc5wwn?errno= ...

  3. IO 文件夹的拷贝

    package FileCopy; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import ja ...

  4. ARTS-S 做事情的正确方法

    有同学改bug的思路是:你们别管我怎么改,先看改的效果对不对.效果对,就这样改,效果不对,我再想别的办法.这样其实把自己关起来,盲目试错,效率太低. 合理的方法应该是和其他大佬们商量一个大家认为正确的 ...

  5. latex常用技巧

    画表格 \usepackage{multirow} \begin{tabular}{cccc} \hline \multicolumn{4}{c}{学生信息}\\ \hline 班级& 姓名& ...

  6. 成为java高手的成长历程想学好java必看

    1:J2SE入门阶段(3-6个月) 学习内容:J2SE常用类,JDBC等等 动态绑定,反射机制等 2:J2EE入门阶段(3个月) 学习内容:JSP/Servlet/JavaBean MVC结构的概念 ...

  7. poj 1321 棋盘问题 (回溯法)

    棋盘问题 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 69951   Accepted: 33143 Descriptio ...

  8. GHOST CMS - 结构 Structure

    Structure Ghost主题包含静态HTML模板,这些模板使用helper类从站点输出数据,并使用定制的CSS进行样式化 A Ghost theme contains static HTML t ...

  9. Python基础-day01-5

    注释 目标 注释的作用 单行注释(行注释) 多行注释(块注释) 01. 注释的作用 使用用自己熟悉的语言,在程序中对某些代码进行标注说明,增强程序的可读性 02. 单行注释(行注释) 以 # 开头,# ...

  10. 安装Visual Studio Code并汉化

    安装很简单,直接点击安装文件,然后一直点击next就可以了.这款软件是免费的,不需要破解. 下载地址 这里需要使用快捷键[Ctrl+Shift+P],在弹出的搜索框中输入[configure lang ...