How to: Show Persistent Objects in a Non-Persistent Object's View

  • 6 min to read

This topic describes how to declare a persistent type reference or collection property in a non-persistent class and display it in the user interface, and optionally assign a default value to it.

Persistent Reference Property

Consider the following non-persistent class:

using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
// ...
[DomainComponent, DefaultClassOptions]
public class NonPersistentObject {
    // ...
    public string Name { get; set; }
    public Person Owner { get; set; }
    // ...
}
NOTE

The INotifyPropertyChanged, IXafEntityObject and IObjectSpaceLink interface implementations were omitted in this example. However, it is recommended to support these interfaces in real-world applications (see PropertyChanged Event in Business Classes and Non-Persistent Objects).

TIP

Use the approach demonstrated in the How to: Perform CRUD Operations with Non-Persistent Objects topic to support saving and loading non-persistent objects from a local cache.

Here, Person is a persistent class from the Business Class Library (for Entity Framework or XPO). Refer to the Add a Class from the Business Class Library (EF) or Add a Class from the Business Class Library (XPO) topic to learn how to add a class from this library. Also, you can use your custom business class instead of Person.

At this stage, the Detail View invoked when creating a new NonPersistentObject, displays the lookup editor for the Owner property. However, the lookup is empty, and you cannot choose any existing Person.

PersistentInNonPresistent1

The NonPersistentObjectSpace created for the current View cannot process the Person persistent object. Follow the steps below to create a persistent Object Space for this type:

  1. Handle the XafApplication.ObjectSpaceCreated event in a module or Controller.
  2. In the event handler, create an additional Object Space for the Person type and add this Object Space to the NonPersistentObjectSpace.AdditionalObjectSpaces collection.

The following example demonstrates how to do this in a platform-agnostic module (MySolution.Module/Module.cs(vb)):

using DevExpress.ExpressApp;
//...
public class MySolutionModule : ModuleBase {
    private void Application_ObjectSpaceCreated(object sender, ObjectSpaceCreatedEventArgs e) {
        if(e.ObjectSpace is NonPersistentObjectSpace) {
            IObjectSpace additionalObjectSpace = Application.CreateObjectSpace(typeof(Person));
            ((NonPersistentObjectSpace)e.ObjectSpace).AdditionalObjectSpaces.Add(additionalObjectSpace);
            e.ObjectSpace.Disposed += (s, args) => {
                additionalObjectSpace.Dispose();
            };
        }
    }
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.ObjectSpaceCreated += Application_ObjectSpaceCreated;
    }
}

The result is demonstrated below.

PersistentInNonPresistent2

Persistent Collection

You can add the Owners collection instead of the Owner reference property:

[DomainComponent, DefaultClassOptions]
public class NonPersistentObject{
    // ... 
    public string Name { get; set; }
    private IList<Person> owners = new List<Person>();
    public IList<Person> Owners {
        get {
            return owners;
        }
    }
}

Users can add and remove Owners via the Link and Unlink Actions after adding the code from the previous section.

PersistentInNonPresistent_Collection

Initialize Persistent Property Values

Implement the IObjectSpaceLink interface in your non-persistent class and use the IObjectSpace.GetObjects<T> method to get required persistent objects.

[DomainComponent, DefaultClassOptions]
public class NonPersistentObject : IObjectSpaceLink {
    public string Name { get; set; }
    private Person owner;
    public Person Owner {
        get {
            if (owner == null) {
                owner = ObjectSpace.GetObjects<Person>(CriteriaOperator.Parse("FirstName='Sam'")).FirstOrDefault();
            }
            return owner;
        }
        set { owner = value; }
    }
    private IList<Person> owners;
    public IList<Person> Owners {
        get {
            if (owners == null) {
                owners = ObjectSpace.GetObjects<Person>(CriteriaOperator.Parse("StartsWith(FirstName, 'B')")) ;
            }
            return owners;
        }
    }
    private IObjectSpace objectSpace;
    [Browsable(false)]
    public IObjectSpace ObjectSpace {
        get { return objectSpace; }
        set { objectSpace = value; }
    }
}

If you create a new NonPersistentObject in UI, its Owner property and Owner collection are initialized:

PersistentInNonPresistent_Init

Important Notes

Note the following if your non-persistent class contains persistent properties and implements IObjectSpaceLink.

When loading such an object from a separate NonPersistentObjectSpace, you get the same object instance linking to the initial Object Space via IObjectSpaceLink.ObjectSpace. If this behavior is unwanted, you can update the Object Space in the NonPersistentObjectSpace.ObjectsGetting event handler. Modify the MySolutionModule class demonstrated in the Persistent Reference Property section as follows:

using DevExpress.ExpressApp;
//...
public class MySolutionNameModule : ModuleBase {
    private void Application_ObjectSpaceCreated(object sender, ObjectSpaceCreatedEventArgs e) {
        if(e.ObjectSpace is NonPersistentObjectSpace) {
            IObjectSpace additionalObjectSpace = Application.CreateObjectSpace(typeof(Person));
            ((NonPersistentObjectSpace)e.ObjectSpace).AdditionalObjectSpaces.Add(additionalObjectSpace);
            ((NonPersistentObjectSpace)e.ObjectSpace).ObjectGetting += ObjectSpace_ObjectGetting;
            e.ObjectSpace.Disposed += (s, args) => {
                ((NonPersistentObjectSpace)s).ObjectGetting -= ObjectSpace_ObjectGetting;
                additionalObjectSpace.Dispose();
            };
        }
    }
    private void ObjectSpace_ObjectGetting(object sender, ObjectGettingEventArgs e) {
        if(e.SourceObject is IObjectSpaceLink) {
            e.TargetObject = e.SourceObject;
            ((IObjectSpaceLink)e.TargetObject).ObjectSpace = (IObjectSpace)sender;
        }
    }
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.ObjectSpaceCreated += Application_ObjectSpaceCreated;
    }
}