expressappframework-403605-business-model-design-orm-unique-auto-increment-number-generation.md
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:
Database-Level: Auto-Increment Database ColumnThis 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)This solution is more complicated and implemented at the ORM level. It does not depend on the database type and also avoids sequence gaps.
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:
Add the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute to the required business object property:
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:
Use the FetchOnly attribute as follows:
FetchOnly attribute.The following example shows how to implement the Programmatic Transaction solution:
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.
Override your business class OnSaved method to update the value on the client side:
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 after new objects are saved:
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;
}
}
}
}
See Also
Web - How to avoid issues with data-bound controls due to missing or non-unique key values