How to: Perform CRUD Operations with Non-Persistent Objects

This topic describes how to implement the create, read, update, and delete operations for non-persistent objects. This example uses the static cache as storage for non-persistent objects.

  1. Implement the following non-persistent class:

    using System;
    using System.ComponentModel;
    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Data;
    using DevExpress.ExpressApp.DC;
    using DevExpress.Persistent.Base;
    // ...
    [DomainComponent, DefaultClassOptions]
    public class NonPersistentClass : IObjectSpaceLink, INotifyPropertyChanged {
        private Int32 id;
        private String name;
        private IObjectSpace objectSpace;
        protected void RaisePropertyChanged(String propertyName) {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public NonPersistentClass(Int32 id, String name)
            : base() {
            this.id = id;
            this.name = name;
        }
        public NonPersistentClass()
            : this(0, "") {
        }
        [Key]
        public Int32 ID {
            get { return id; }
            set { id = value; }
        }
        public String Name {
            get { return name; }
            set {
                if (name != value) {
                    name = value;
                    RaisePropertyChanged(nameof(Name));
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        [Browsable(false)]
        public IObjectSpace ObjectSpace {
            get { return objectSpace; }
            set { objectSpace = value; }
        }
    }
    
  2. Open the WinApplication.cs (WinApplication.vb), WebApplication.cs (WebApplication.vb), and/or MobileApplication.cs (MobileApplication.vb) file in a C#/VB Editor. Ensure that the NonPersistentObjectSpaceProvider is registered in the overridden CreateDefaultObjectSpaceProvider method (in addition to the existing XPObjectSpaceProvider or EFObjectSpaceProvider). The Solution Wizard adds this code automatically. Note that this code may be missing if you created your project in an older XAF version.

    protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
        // ...
        args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo, null));
    }
    
  3. In a module project, access the NonPersistentObjectSpace and handle its events listed below.

    The following code shows how to do this:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using DevExpress.ExpressApp;
    // ...
    public sealed partial class MyModule : ModuleBase {
        private static Dictionary<int, NonPersistentClass> objectsCache;
        static MyModule() {
            objectsCache = new Dictionary<int, NonPersistentClass>();
            objectsCache.Add(0, new NonPersistentClass(0, "A"));
            objectsCache.Add(1, new NonPersistentClass(1, "B"));
            objectsCache.Add(2, new NonPersistentClass(2, "C"));
            objectsCache.Add(3, new NonPersistentClass(3, "D"));
            objectsCache.Add(4, new NonPersistentClass(4, "E"));
        }
        //...
        public override void Setup(XafApplication application) {
            base.Setup(application);
            application.SetupComplete += Application_SetupComplete;
        }
        private void Application_SetupComplete(object sender, EventArgs e) {
            Application.ObjectSpaceCreated += Application_ObjectSpaceCreated;
        }
        private void Application_ObjectSpaceCreated(object sender, ObjectSpaceCreatedEventArgs e) {
            NonPersistentObjectSpace nonPersistentObjectSpace = e.ObjectSpace as NonPersistentObjectSpace;
            if(nonPersistentObjectSpace != null) {
                nonPersistentObjectSpace.ObjectsGetting += NonPersistentObjectSpace_ObjectsGetting;
                nonPersistentObjectSpace.ObjectByKeyGetting += NonPersistentObjectSpace_ObjectByKeyGetting;
                nonPersistentObjectSpace.ObjectGetting += NonPersistentObjectSpace_ObjectGetting;
                nonPersistentObjectSpace.Committing += NonPersistentObjectSpace_Committing;
            }
        }
        private void NonPersistentObjectSpace_ObjectsGetting(Object sender, ObjectsGettingEventArgs e) {
            if(e.ObjectType == typeof(NonPersistentClass)) {
                IObjectSpace objectSpace = (IObjectSpace)sender;
                BindingList<NonPersistentClass> objects = new BindingList<NonPersistentClass>();
                objects.AllowNew = true;
                objects.AllowEdit = true;
                objects.AllowRemove = true;
                foreach(NonPersistentClass obj in objectsCache.Values) {
                    objects.Add(objectSpace.GetObject<NonPersistentClass>(obj));
                }
                e.Objects = objects;
            }
        }
        private void NonPersistentObjectSpace_ObjectByKeyGetting(object sender, ObjectByKeyGettingEventArgs e) {
            IObjectSpace objectSpace = (IObjectSpace)sender;
            if(e.ObjectType == typeof(NonPersistentClass)) {
                NonPersistentClass obj;
                if(objectsCache.TryGetValue((int)e.Key, out obj)) {
                    e.Object = objectSpace.GetObject(obj);
                }
            }
        }
        private void NonPersistentObjectSpace_ObjectGetting(object sender, ObjectGettingEventArgs e) {
            if(e.SourceObject is NonPersistentClass) {
                ((IObjectSpaceLink)e.TargetObject).ObjectSpace = (IObjectSpace)sender;
            }
        }
        private void NonPersistentObjectSpace_Committing(Object sender, CancelEventArgs e) {
            IObjectSpace objectSpace = (IObjectSpace)sender;
            foreach(Object obj in objectSpace.ModifiedObjects) {
                NonPersistentClass myobj = obj as NonPersistentClass;
                if(obj != null) {
                    if(objectSpace.IsNewObject(obj)) {
                        int key = objectsCache.Count;
                        myobj.ID = key;
                        objectsCache.Add(key, myobj);
                    }
                    else if(objectSpace.IsDeletedObject(obj)) {
                        objectsCache.Remove(myobj.ID);
                    }
                }
            }
        }
    }
    
    TIP

    Refer to the following GitHub repository to see the extended example: How to implement CRUD operations for Non-Persistent Objects stored remotely.

Important Notes

  1. A non-persistent Object Space does not track changes of original objects and does not add changed objects to the ModifiedObjects collection. You can use the IObjectSpace.SetModified(Object) method to add changed objects to this collection explicitly. If a non-persistent object implements the INotifyPropertyChanged interface, you can set AutoSetModifiedOnObjectChange / AutoSetModifiedOnObjectChangeByDefault to true to automatically add the changed object to the ModifiedObjects collection when PropertyChanged is raised.

  2. 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.

See Also