A newer version of this page is available. Switch to the current version.

PersistenceValidationController Class

Validates persistent objects when they are saved or deleted in the UI.

Namespace: DevExpress.ExpressApp.Validation

Assembly: DevExpress.ExpressApp.Validation.v19.1.dll


public class PersistenceValidationController :


This Controller is activated in root Detail Views and List Views. To provide validation in the particular Context, the Controller subscribes to the IObjectSpace.Committing and IObjectSpace.CustomDeleteObjects event of the current View’s Object Space. The table below contains peculiarities of this process in the Save and Delete contexts .

Save Context Delete Context
Handled event IObjectSpace.Committing IObjectSpace.CustomDeleteObjects
Validated objects The View.CurrentObject, its aggregated objects and other modified objects. The objects marked for deletion and their aggregated objects.
Event handler behavior The Controller checks all validation rules from the RuleSet.RegisterRules collection associated with the Save validation context. If at least one rule is broken, the Controller cancels the Save Action execution and raises a validation exception. The Controller checks all validation rules associated with the Delete validation context. If at least one rule is broken, the Controller cancels the Delete Action execution and raises a validation exception.
Failed validation result New and modified objects are not saved to the database. The current Object Space and all editors have the same state as before committing. No objects are deleted from the database. The current View and Object Space stay unchanged.
Passed validation result All new and modified objects are saved to the database. All objects that are marked for deletion are deleted in the current Object Space, and will be deleted from the database after the IObjectSpace.CommitChanges method execution. This method is executed immediately if the DeleteObjectsViewController.AutoCommit property is true. Otherwise, the CommitChanges method is executed when you save changes.



The PersistenceValidationController exposes several events that allow you to customize the default validation process.

Event Description
PersistenceValidationController.ContextValidating Handle this event to modify the collection of objects which will be validated in the current context.
PersistenceValidationController.CustomGetAggregatedObjectsToValidate Handle this event to manually specify aggregated objects to be validated.
PersistenceValidationController.NeedToValidateObject Handle this event to exclude particular objects from validation.

The example below demonstrates how you can use the PersistenceValidationController class and the events described in the table above.

For example, adjust the rules for the Person class, which has an aggregated collection of Address objects and a non-aggregated collection of the Story objects. The code snippet below demonstrates these classes decorated with the RuleCriteriaAttribute.

using DevExpress.Persistent.Base;
using DevExpress.Persistent.Validation;
using DevExpress.Xpo;
[RuleCriteria("AssressRule", DefaultContexts.Save, "City == 'Tokyo' or Owner.Name != 'Sam'", 
"Address message", SkipNullOrEmptyValues = false)]
public class Address : XPObject {
    private string city;
    public string City {
        get { return city; }
        set { SetPropertyValue("City", ref city, value); }
    public Address(Session session)
        : base(session) {
    public Person Owner;
[RuleCriteria("PersonRule", DefaultContexts.Save, "Name != 'John'", 
"Person message", SkipNullOrEmptyValues = false)]
public class Person : XPObject {
    public Person(Session session)
        : base(session) {
    private string name;
    public string Name {
        get { return name; }
        set { SetPropertyValue("Name", ref name, value); }
    [DevExpress.Xpo.Aggregated, Association("PersonAddresses")]
    public XPCollection<Address> Addresses {
        get { return GetCollection<Address>("Addresses"); }
    public XPCollection<Story> Stories {
        get { return GetCollection<Story>("Stories"); }
[RuleCriteria("HistoryRule", DefaultContexts.Save, "Owner == null or Owner.Name != 'Bob'", 
"History message", SkipNullOrEmptyValues = false)]
public class Story : XPObject {
    private string story;
    public string StoryText {
        get { return story; }
        set { SetPropertyValue("StoryText", ref story, value); }
    public Story(Session session)
        : base(session) {
    private Person owner;
    public Person Owner {
        get { return owner; }
        set { SetPropertyValue("Owner", ref owner, value); }

The following rules are formed for validating the objects above.

  • The Address objects do not need to be validated if their City property is set to Tokyo.
  • Aggregated objects need to be validated if the root object is modified.
  • When the current object is Person, it is validated only if this object was modified. Aggregated objects modifications are ignored.
  • If the Person object is modified, all objects from its Stories collection are checked.

Create a new controller which uses the PersistenceValidationController controller to validate objects depending on the rules above. The NeedToValidateObject event is handled here to specify whether the objects with a particular property value need to be validated or not. The CustomGetAggregatedObjectsToValidate event is used to modify a collection of aggregated objects to validate. The ContextValidating event allows organizing a collection of all objects to be validated in the particular context.

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Validation;
public class CustomValidationController : ViewController {
    PersistenceValidationController pController;
    protected override void OnActivated() {
        pController = Frame.GetController<PersistenceValidationController>();
        if(pController != null) {
            pController.ContextValidating += PController_ContextValidating;
            pController.NeedToValidateObject += PController_NeedToValidateObject;
            pController.CustomGetAggregatedObjectsToValidate += 
    private void PController_CustomGetAggregatedObjectsToValidate(object sender, 
CustomGetAggregatedObjectsToValidateEventArgs e) {
        if(!ObjectSpace.IsObjectToSave(e.OwnerObject)) {
            e.Handled = true;
    private void PController_NeedToValidateObject(object sender, NeedToValidateObjectEventArgs e) {
        if(e.CurrentObject is Address && ((Address)e.CurrentObject).City == "Tokyo") {
            e.NeedToValidate = false;
    private void PController_ContextValidating(object sender, ContextValidatingEventArgs e) {
        Person person = View.CurrentObject as Person;
        if (e.Context.Id == "Save" && person != null) {
            if (ObjectSpace.IsObjectToSave(person)) {
                foreach (object obj in person.Stories) {
            else {



See Also