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. DRF Django REST framework 之 视图组件(四)

    引言 在我们有几十上百的视图类,都有get,post等方法,在功能类似时,会导致大量的重复代码出现,显然还有很多可以优化的地方.这也就有了视图组件,它的功能非常强大,能很好的优化接口逻辑. 视图组件 ...

  2. iOS全局处理键盘事件

    转自:http://www.cnblogs.com/xinus/archive/2013/01/22/ios-keybord-notification.html 注册监听键盘事件的通知 [[NSNot ...

  3. DOM中的获得元素的方式

    获取元素的方式:分为俩种: 1.直接获取:直接获取分为三种: a,获取单个元素: function demo1(){ var uid=document.getElementById("use ...

  4. [TimLinux] Python IDE工具

    1. 首推IDE工具PyCharm JetBrains公司推出的系列IDE工具中支持Python编译语言的开发工具,基本上可以认为是行业第一IDE工具了,分为社区版和专业版,可以创建纯Python单文 ...

  5. Redis 命令执行过程(下)

    在上一篇文章中<Redis 命令执行过程(上)>中,我们首先了解 Redis 命令执行的整体流程,然后细致分析了从 Redis 启动到建立 socket 连接,再到读取 socket 数据 ...

  6. I/O中断原理

    目录 I/O中断原理 前言 什么是中断 中断类型 硬件中断 软件中断 I/O中断流程 无中断 有中断 中断处理 相关文献 I/O中断原理 前言 在Windows内核原理-同步IO与异步IO和<高 ...

  7. JavaScript中的"奇奇怪怪"

    filter等方法的隐式转化 var list = [1,,2,,0,5,9];console.log(list[1]); // console: undefinedconsole.log(list[ ...

  8. Beego在views中格式化显示时间(int64转string)

    最近在使用beego开发系统的过程中,遇到时间转换问题,需求如下: 通过以下函数获取Unix时间戳,后台数据库格式为int64: time.Now().Unix() 效果图: 从数据库获取数据,直接以 ...

  9. MySQL 05

    目录 事务 基本概念 四大特性(ACID) 使用方法 存储引擎 视图 基本概念 使用方法 触发器 基本概念 使用方法 存储过程 基本概念 使用方法 数据备份 备份 导入 函数 事务 基本概念 事务: ...

  10. Orleans 初接触(一) 入门例子

    [返回导航] 在简单了解了Orleans 之后我们可以通过几个例子去加深印象 一.Orleans入门例子 这个例子是跟着<Orleans入门例子>(https://www.cnblogs. ...