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

This topic describes how to declare a reference or collection property of a persistent type in a non-persistent class and display it in the UI.

Persistent Reference Property

Implement 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 the save and load operations for non-persistent objects.

In this example, Person is a persistent class from the Business Class Library. You can use a custom business class instead of Person.

You can run the application and create a new NonPersistentObject. In its Detail View, the lookup editor for the Owner property 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 {
    //...
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.ObjectSpaceCreated += Application_ObjectSpaceCreated;
    }
    private void Application_ObjectSpaceCreated(object sender, ObjectSpaceCreatedEventArgs e) {
        var nonPersistentObjectSpace = e.ObjectSpace as NonPersistentObjectSpace;
        if(nonPersistentObjectSpace != null) {
            IObjectSpace additionalObjectSpace = Application.CreateObjectSpace(typeof(Person));
            nonPersistentObjectSpace.AdditionalObjectSpaces.Add(additionalObjectSpace);
            nonPersistentObjectSpace.AutoDisposeAdditionalObjectSpaces = true;
        }
    }
}

The image below demonstrates the result.

PersistentInNonPresistent2

Persistent Collection

You can add the Owners collection instead of the Owner reference property, as shown below.

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

To allow users to add and remove Owners via the Link and Unlink Actions, create an additional Object Space for the Person type, as demonstrated in the previous section.

Initialize Persistent Property Values

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

using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
// ...
[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;
        }
        internal set { owners = value; }
    }
    private IObjectSpace objectSpace;
    [Browsable(false)]
    public IObjectSpace ObjectSpace {
        get { return objectSpace; }
        set { objectSpace = value; }
    }
}

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

Refresh Linked Persistent Objects

The Refresh Action does not affect non-persistent object Views. Follow the steps below to allow reloading non-persistent objects and persistent objects linked to them.

  1. Access the NonPersistentObjectSpace and set its AutoRefreshAdditionalObjectSpaces property to true.
  2. Subscribe to the NonPersistentObjectSpace.ObjectGetting event. In the event handler, create a new instance of the non-persistent object and copy property values from the source object. To create copies of persistent objects linked to the non-persistent objects, use the IObjectSpace.GetObject method.
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Xpo;
using DevExpress.Persistent.BaseImpl;
//...
public class MySolutionModule : ModuleBase {
    //...
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.ObjectSpaceCreated += Application_ObjectSpaceCreated;
    }
    private void Application_ObjectSpaceCreated(object sender, ObjectSpaceCreatedEventArgs e) {
        NonPersistentObjectSpace nonPersistentObjectSpace = e.ObjectSpace as NonPersistentObjectSpace;
        if(nonPersistentObjectSpace != null) {
            IObjectSpace additionalObjectSpace = Application.CreateObjectSpace(typeof(Person));
            nonPersistentObjectSpace.AdditionalObjectSpaces.Add(additionalObjectSpace);
            nonPersistentObjectSpace.AutoDisposeAdditionalObjectSpaces = true;
            nonPersistentObjectSpace.AutoRefreshAdditionalObjectSpaces = true;
            nonPersistentObjectSpace.ObjectGetting += ObjectSpace_ObjectGetting;
        }
    }
    private void ObjectSpace_ObjectGetting(object sender, ObjectGettingEventArgs e) {
        var objectSpace = (IObjectSpace)sender;
        if(e.SourceObject is NonPersistentObject) {
            var sourceObject = (NonPersistentObject)e.SourceObject;
            var targetObject = new NonPersistentObject();
            targetObject.Owner = objectSpace.GetObject<Person>(sourceObject.Owner);
            var owners = new List<Person>();
            foreach(var owner in sourceObject.Owners) {
                owners.Add(objectSpace.GetObject<Person>(owner));
            }
            targetObject.Owners = owners;
            e.TargetObject = targetObject;
        }
    }
}

If you modify and save a Person in another View or in a database while the NonPersistentObject Detail View is open, click the Refresh Action to refresh data in this View.

For a more complex example of non-persistent object with linked persistent objects, refer to the following GitHub example: How to refresh Non-Persistent Objects and reload nested Persistent Objects.

Important Notes

We recommend that you do not share non-persistent objects when they implement IObjectSpaceLink or have linked persistent objects because of the following limitations.

  • You can use a shared (static) storage for non-persistent objects only if a single NonPersistentObjectSpace works with these objects at any time. Non-persistent objects that implement IObjectSpaceLink cannot belong to multiple Object Spaces simultaneously. When you change the IObjectSpaceLink.ObjectSpace property to a different Object Space, dispose of the previously used Object Space. Otherwise, object changes can trigger events in multiple Views and cause conflicts or unexpected behavior.
  • You cannot share persistent objects between Object Spaces.

Instead of sharing non-persistent objects, create new instances in each NonPersistentObjectSpace. If you want to preserve data from all instances of a non-persistent object, store this data separately.