Skip to main content
.NET 6.0+

IXafEntityObject Interface

Declares methods that are called automatically when a business object is being created, loaded and saved.

Namespace: DevExpress.ExpressApp

Assembly: DevExpress.ExpressApp.v23.2.dll

NuGet Package: DevExpress.ExpressApp

Declaration

public interface IXafEntityObject

Remarks

When a business object supports IXafEntityObject, the Object Space automatically calls the IXafEntityObject.OnCreated, IXafEntityObject.OnLoaded and IXafEntityObject.OnSaving methods of this interface when an object is being created, loaded and saved. Thus, you can implement these methods and add certain business logic directly in the business object code, without the use of Controllers. In most cases, you may need to access other business objects from your code, so you can implement the IObjectSpaceLink interface to access an IObjectSpace instance and use its methods to query objects.

Note

  • The IXafEntityObject interface is intended for use with Entity Framework and Non-Persistent Objects. For eXpress Persistent Objects (XPO), use the BaseObject.AfterConstruction and BaseObject.OnSaving methods.
  • You can use the XAF Business Object | EF Core Business Object from Template Gallery to add a class that supports both IXafEntityObject and IObjectSpaceLink.

In the example below, the CreatedBy property refers to the user who created the current object, the LastModifiedBy property specifies the user who last changed the object, and the IsNew property indicates if an object is only created, but not saved. For example, you can use this property in Conditional Appearance and Validation rules.

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.Persistent.Base;
using YourApplicaionName.Module.BusinessObjects;
[DefaultClassOptions]
public class MyEntityObject : IXafEntityObject {
    [Key, Browsable(false)]
    public virtual Guid ID { get; protected set; }
    public virtual string Name { get; set; }
    [NotMapped]
    public bool IsNew { get; protected set; }
    public virtual ApplicationUser CreatedBy { get; protected set; }
    public virtual ApplicationUser LastModifiedBy { get; protected set; }
    ApplicationUser GetCurrentUser() {
        return ObjectSpace.GetObjectByKey<ApplicationUser>(
            ObjectSpace.ServiceProvider.GetRequiredService<ISecurityStrategyBase>().
                UserId);
    }
    void IXafEntityObject.OnCreated() {
        CreatedBy = GetCurrentUser();
        IsNew = true;
    }
    void IXafEntityObject.OnLoaded() {
        IsNew = false;
    }
    void IXafEntityObject.OnSaving() {
        if(ObjectSpace != null) {
            LastModifiedBy = GetCurrentUser();
        }
        IsNew = false;
    }
    IObjectSpace ObjectSpace {
        get {
            return ((IObjectSpaceLink)this).ObjectSpace;
        }
    }
}

// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.

You can also inherit your class from the DevExpress.Persistent.BaseImpl.EF.BaseObject class that implements this interface:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl.EF;
using YourApplicaionName.Module.BusinessObjects;
[DefaultClassOptions]
public class MyEntityObject : BaseObject {
    public virtual string Name { get; set; }
    [NotMapped]
    public bool IsNew { get; protected set; }
    public virtual ApplicationUser CreatedBy { get; protected set; }
    public virtual ApplicationUser LastModifiedBy { get; protected set; }
    ApplicationUser GetCurrentUser() {
        return ObjectSpace.GetObjectByKey<ApplicationUser>(
            ObjectSpace.ServiceProvider.GetRequiredService<ISecurityStrategyBase>().
                UserId);
    }
    public override void OnCreated() {
        CreatedBy = GetCurrentUser();
        IsNew = true;
    }
    public override void OnLoaded() {
        IsNew = false;
    }
    public override void OnSaving() {
        if(ObjectSpace != null) {
            LastModifiedBy = GetCurrentUser();
        }
        IsNew = false;
    }
}

Note that in the OnSaving method, you need to check if an Object Space is null (Nothing in VB). The reason is that the OnSaving method is also called when the current business object is being deleted and the link to the Object Space is already cleared at that moment to avoid memory leaks. If you want to access the Object Space on object deletion, change the IObjectSpaceLink.ObjectSpace property implementation to maintain the Object Space reference.

private IObjectSpace objectSpace;
IObjectSpace IObjectSpaceLink.ObjectSpace {
    get { return objectSpace; }
    set { if (value != null) objectSpace = value; }
}

In this instance, you should manually set the Object Space to null (Nothing in VB) on deletion. Use the IObjectSpace.IsObjectToDelete method to determine whether an object is being saved or deleted:

void IXafEntityObject.OnSaving() {
    ApplicationUser currentUser = ObjectSpace.GetObjectByKey<ApplicationUser>(
            ObjectSpace.ServiceProvider.GetRequiredService<ISecurityStrategyBase>().
                UserId);
    if (objectSpace.IsObjectToDelete(this)) {
        // Executed on deletion:
        Tracing.Tracer.LogWarning("The '{0}' user is deleting the '{1}' object", currentUser.UserName, Name);
        objectSpace = null; 
    }
    else {
        // Executed on saving:
        LastModifiedBy = currentUser;
    }
}
See Also