Auto-Generate Unique Number Sequence(自动生成唯一数字序列)
Orders, Invoices, Articles, and other business entities often require an auto-filled Number or Code field that users can memorize. Although these user-friendly field values are sequential, gaps are permitted (for example, when a user deletes an order). Use one of the following techniques to use this field in XAF applications:
订单、发票、商品和其他业务实体通常需要用户可以记忆的自动填充数字或代码字段。尽管这些用户友好的字段值是顺序的,但允许有空隙(例如,当用户删除订单时)。使用以下技术之一在XAF应用程序中使用此字段:
Database-Level: Auto-Increment Database Column(数据库级:自动增量数据库列)
This solution avoids sequence gaps. Since this solution is implemented at the database level, it is specific to the database type.
此解决方案避免了序列间隙。由于此解决方案是在数据库级别实现的,因此它特定于数据库类型。
ORM-Level: Programmatic Transaction (XPO Only)(ORM级别:编程事务(仅限XPO))
This solution is more complicated and implemented at the ORM level. It does not depend on the database type and also avoids sequence gaps.
这种解决方案更复杂,在ORM级别实现。它不依赖于数据库类型,也避免了序列间隙。
Database-Level: Auto-Increment Database Column(数据库级:自动增量数据库列)
EF Core
Use the following steps to generate sequential values for business object properties to ensure that these properties are assigned a value when their respective objects are saved to the database:
使用以下步骤为业务对象属性生成顺序值,以确保在将这些属性的相应对象保存到数据库时为这些属性分配一个值:
1.Add the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute to the required business object property:
将[Database aseGenerated(DatabaseGeneratedOption. Identity)]属性添加到所需的业务对象属性:
cs
public class Address : BaseObject {
// ...
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual long SequentialNumber { get; set; }
// ...
}
2.Add the following code snippet to the DbContext’s OnModelCreating method implementation to ensure that the generated values are always displayed in the UI immediately after the object has been saved:
将以下代码片段添加到DbContext的OnModelCreating方法实现中,以确保生成的值始终在对象保存后立即显示在UI中:
cs
public class GenerateUserFriendlyIdEFCoreDbContext : DbContext {
// ...
protected override void OnModelCreating(ModelBuilder modelBuilder) {
// ...
modelBuilder.Entity<Address>().UsePropertyAccessMode(PropertyAccessMode.FieldDuringConstruction);
}
}
XPO
Use the FetchOnly attribute as follows:
使用FetchOnly属性如下:
1.Create an auto-increment database column (for example, Identity in SQL Server).
创建自动增量数据库列(例如,SQL服务器中的身份)。
2.Create a persistent property mapped to this column and decorate it with the FetchOnly attribute.
创建一个映射到此列的持久属性并使用FetchOnly属性对其进行装饰。
ORM-Level: Programmatic Transaction (XPO Only)(ORM级别:编程事务(仅限XPO))
Refresh the Identifier Field Value in the UI(刷新UI中的标识符字段值)
If you use the Programmatic Transaction solution with UI-Level security, an application displays the identifier field value immediately after a user creates a new object. In the Integrated Mode and Middle-Tier Application Server configuration, the newly generated sequence number is displayed only after a manual refresh. XAF does not pass the sequence to the client immediately. Implement one of the techniques described below to refresh the field value automatically.
如果您使用具有UI级安全性的编程事务解决方案,应用程序会在用户创建新对象后立即显示标识符字段值。在集成模式和中间层应用程序服务器配置中,只有在手动刷新后才会显示新生成的序列号。XAF不会立即将序列传递给客户端。实施下面描述的技术之一来自动刷新字段值。
Override the Business Class OnSaved Method(覆盖业务类OnSaved方法)
Override your business class OnSaved method to update the value on the client side:
覆盖您的业务类OnSaved方法以更新客户端的值:
C#
namespace MySolution.Module.BusinessObjects {
public class YourBusinessClass : YourBaseXpoClass {
// ...
protected override void OnSaved() {
base.OnSaved();
if(Number == 0) { // 0 is the default value of the sequence number property.
Session.Reload(this);
}
}
// ...
}
}
Use a Custom Controller to Reload the Object Space(使用自定义控制器重新加载对象空间)
Use a custom Controller to reload the Object Space after new objects are saved:
保存新对象后,使用自定义控制器重新加载对象空间:
C#
namespace MySolution.Module.Controllers {
// ...
public class RefreshAfterCommitController : ViewController {
bool needRefresh = false;
public RefreshAfterCommitController() {
TargetViewNesting = Nesting.Root;
}
protected override void OnActivated() {
base.OnActivated();
ObjectSpace.Committed += ObjectSpace_Committed;
ObjectSpace.Committing += ObjectSpace_Committing;
ObjectSpace.Reloaded += ObjectSpace_Reloaded;
}
protected override void OnDeactivated() {
ObjectSpace.Committed -= ObjectSpace_Committed;
ObjectSpace.Committing -= ObjectSpace_Committing;
ObjectSpace.Reloaded -= ObjectSpace_Reloaded;
base.OnDeactivated();
}
private void ObjectSpace_Reloaded(object sender, EventArgs e) {
needRefresh = false;
}
private void ObjectSpace_Committing(object sender, System.ComponentModel.CancelEventArgs e) {
var objectSpace = (IObjectSpace)sender;
foreach (var obj in objectSpace.GetObjectsToSave(false)) {
if (objectSpace.IsNewObject(obj)) {
needRefresh = true; break;
}
}
}
private void ObjectSpace_Committed(object sender, EventArgs e) {
if (needRefresh) {
((IObjectSpace)sender).Refresh();
needRefresh = false;
}
}
}
}