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. 关于iframe/子窗体与父窗体的交互

    父子窗体交互方式 通过contentWindow交互 通过postMessage交互 通过contentWindow交互 主窗体内嵌的iframe或者是其通过js打开的新窗口都可以通过contentW ...

  2. VMware下载及安装使用方法

    一.VMware的介绍: 虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的.运行在一个完全隔离环境中的完整计算机系统.DesktopVirtualBox,虚拟系统通过生成 ...

  3. 求局域网内所有在线主机的ip

    在一个局域网内,已知其中一台主机的ip为192.,子网掩码为255.,求所有其他在线主机的ip. shell 编码实现 #!/bin/bash netWorkIP=. ) do $netWorkIP$ ...

  4. Tomcat下载安装并部署到IDEA(附带idea两种热部署设置方法)

    目录 Tomcat下载教程 Tomcat安装教程 Tomcat热部署到IDEA idea两种热部署设置方法 使用Idea的时候,修改了代码,需要反复的重启Tomcat,查看效果,是不是贼烦?还记得刚上 ...

  5. 【实用工具】使用Java封装可执行exe应用全过程

    目录 编写java代码 打包 创建exe文件 压缩 总结 本文将使用exe4j将java项目封装为可以发送给他人使用的工具为例,来记录将java项目封装为exe文件的全过程 编写java代码 目标:创 ...

  6. 设计模式GOF23(创建型模式)

    • 创建型模式:  单例模式.工厂模式.抽象工厂模式.建造者模式.原型模式.   • 结构型模式: –适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式.   • 行为型模式: 模 ...

  7. seaborn 数据可视化(一)连续型变量可视化

    一.综述 Seaborn其实是在matplotlib的基础上进行了更高级的API封装,从而使得作图更加容易,图像也更加美观,本文基于seaborn官方API还有自己的一些理解.   1.1.样式控制: ...

  8. Python脚本之三种运行方式,你会几个?

    前言本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:Jeremy_Lee123  一.交互模式下执行 Python 这种模式 ...

  9. 从FPGA搞定OV7670 VGA显示 移植到 STM32F10x TFT显示 总结及疑问(高手请进)

    OV7670不愧是最便宜的摄像头了最大显示像素:640*480(在VGA显示器上显示效果还不赖,用usb模块采集显示依然显著) 第一步:VGA显示 视频图像(实时)FPGA+SDRAM+OV7670= ...

  10. Cisco packet tracer 的手动添加模块

    在PacketTracer 里面,路由器都是基本配置,这和真实设备是相同的 基本配置里面2620只有一个以太网口: 而2621和2811在背板上有两个以太网接口 所以,你在show run里面可以看到 ...