Skip to main content
.NET 6.0+

How to: Perform CRUD Operations with Non-Persistent Objects

  • 7 minutes to read

This topic describes how to implement the create, read, update, and delete operations for non-persistent objects. This example uses ValueManager to access the storage of non-persistent objects.

  1. Implement the following non-persistent class:

    using System;
    using System.ComponentModel;
    using DevExpress.ExpressApp.Data;
    using DevExpress.ExpressApp.DC;
    using DevExpress.Persistent.Base;
    // ...
    [DomainComponent, DefaultClassOptions]
    public class NonPersistentClass : INotifyPropertyChanged {
        private Int32 id;
        private String name;
        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, Browsable(false)]
        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;
    }
    
  2. Open the WinApplication.cs (WinApplication.vb), WebApplication.cs (WebApplication.vb), and/or BlazorApplication.cs 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;
    using DevExpress.Persistent.Base;
    // ...
    public sealed partial class MyModule : ModuleBase {
        private static Dictionary<int, NonPersistentClass> ObjectsCache {
            get {
                var manager = ValueManager.GetValueManager<Dictionary<int, NonPersistentClass>>("NP");
                Dictionary<int, NonPersistentClass> objectsCache = (manager.CanManageValue) ? manager.Value : null;
                if(objectsCache == null) {
                    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"));
                    if(manager.CanManageValue) {
                        manager.Value = objectsCache;
                    }
                }
                return objectsCache;
            }
        }
        //...
        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.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_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. If a non-persistent object implements IObjectSpaceLink and its ObjectSpace property value doesn’t match the Object Space that manipulates the object, the following exception is thrown: ‘An error with the number 1021 has occurred. Error message: The object that was edited belongs to a different ObjectSpace. This error can occur if you manipulate your objects via an ObjectSpace to which these objects do not belong.’

    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 the example in the FeatureCenter.Module\NonPersistentObjects\Controllers.cs file (the NonPersistentObjectSpaceExtender class) in the Feature Center demo that is installed in the %PUBLIC%\Documents\DevExpress Demos 23.2\Components\XAF\FeatureCenter.NETFramework.XPO folder.

    For more information, refer to the following Breaking Change description: Core - Error 1021 may occur if a non-persistent object implements IObjectSpaceLink and shared between different Object Spaces.

See Also