Example E4565
Visible to All Users

XAF - How to show audit entries for a current object and its aggregated objects in one list

This example demonstrated how to show audit information about a current object and each object in its collection property:
image

Implementation Details

  1. Introduce a new non-persistent CustomAuditDataItem class that is used to display the audit information:
C#
[DomainComponent] public class CustomAuditDataItem { private AuditDataItemPersistent sourceAuditDataItem; private string targetObjectName; public CustomAuditDataItem(AuditDataItemPersistent sourceAuditDataItem, string targetObjectName) { this.sourceAuditDataItem = sourceAuditDataItem; this.targetObjectName = targetObjectName; } public string TargetObjectName { get { return targetObjectName; } } public string Description { get { return sourceAuditDataItem.Description; } } public DateTime ModifiedOn { get { return sourceAuditDataItem.ModifiedOn; } } public string NewValue { get { return sourceAuditDataItem.NewValue; } } public string OldValue { get { return sourceAuditDataItem.OldValue; } } public string OperationType { get { return sourceAuditDataItem.OperationType; } } public string PropertyName { get { return sourceAuditDataItem.PropertyName; } } public string UserName { get { return sourceAuditDataItem.UserName; } } }
  1. In the business class, introduce a new collection property to return an extended list of required audit entries:
C#
using DevExpress.ExpressApp; using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl.EF; using DevExpress.Persistent.BaseImpl.EFCore.AuditTrail; using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.DataAnnotations.Schema; namespace dxTestSolution.Module.BusinessObjects; [DefaultClassOptions] public class Contact : BaseObject { public virtual string FirstName { get; set; } public virtual string LastName { get; set; } public virtual int Age { get; set; } public virtual DateTime BirthDate { get; set; } public virtual ObservableCollection<MyTask> MyTasks { get; set; } = new ObservableCollection<MyTask>(); private BindingList<CustomAuditDataItem> auditTrail; [CollectionOperationSet(AllowAdd = false, AllowRemove = false)] [NotMapped] public virtual BindingList<CustomAuditDataItem> AuditTrail { get { if (auditTrail == null) { auditTrail = new BindingList<CustomAuditDataItem>(); auditTrail.AllowEdit = false; auditTrail.AllowNew = false; auditTrail.AllowRemove = false; IList<AuditDataItemPersistent> rootItems = AuditDataItemPersistent.GetAuditTrail(ObjectSpace, this); if (rootItems != null) { foreach (AuditDataItemPersistent entry in rootItems) { auditTrail.Add(new CustomAuditDataItem(entry, "Contact")); } } foreach (MyTask task in MyTasks) { IList<AuditDataItemPersistent> taskItems = AuditDataItemPersistent.GetAuditTrail(ObjectSpace, task); if (taskItems != null) { foreach (AuditDataItemPersistent entry in taskItems) { auditTrail.Add(new CustomAuditDataItem(entry, "Task - " + task.Subject)); } } } } return auditTrail; } } }

Files to Review

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

EF/ExtendAuditEF/ExtendAuditEF.Module/BusinessObjects/CustomAuditDataItem.cs
C#
using System; using System.Collections.Generic; using System.Text; using DevExpress.ExpressApp.DC; using DevExpress.Persistent.BaseImpl; using DevExpress.ExpressApp; using DevExpress.Persistent.BaseImpl.EFCore.AuditTrail; namespace dxTestSolution.Module.BusinessObjects { [ DomainComponent] public class CustomAuditDataItem: NonPersistentBaseObject { private AuditDataItemPersistent sourceAuditDataItem; private string targetObjectName; public CustomAuditDataItem(AuditDataItemPersistent sourceAuditDataItem, string targetObjectName) { this.sourceAuditDataItem = sourceAuditDataItem; this.targetObjectName = targetObjectName; } public string TargetObjectName { get { return targetObjectName; } } public string Description { get { return sourceAuditDataItem.Description; } } public DateTime ModifiedOn { get { return sourceAuditDataItem.ModifiedOn; } } public string NewValue { get { return sourceAuditDataItem.NewValue; } } public string OldValue { get { return sourceAuditDataItem.OldValue; } } public string OperationType { get { return sourceAuditDataItem.OperationType; } } public string PropertyName { get { return sourceAuditDataItem.PropertyName; } } public string UserName { get { return sourceAuditDataItem.UserName; } } } }
EF/ExtendAuditEF/ExtendAuditEF.Module/BusinessObjects/Contact.cs
C#
using DevExpress.ExpressApp; using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl.EF; using DevExpress.Persistent.BaseImpl.EFCore.AuditTrail; using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.DataAnnotations.Schema; namespace dxTestSolution.Module.BusinessObjects; [DefaultClassOptions] public class Contact : BaseObject { public virtual string FirstName { get; set; } public virtual string LastName { get; set; } public virtual int Age { get; set; } public virtual DateTime BirthDate { get; set; } public virtual ObservableCollection<MyTask> MyTasks { get; set; } = new ObservableCollection<MyTask>(); private BindingList<CustomAuditDataItem> auditTrail; [CollectionOperationSet(AllowAdd = false, AllowRemove = false)] [NotMapped] public virtual BindingList<CustomAuditDataItem> AuditTrail { get { if (auditTrail == null) { auditTrail = new BindingList<CustomAuditDataItem>(); auditTrail.AllowEdit = false; auditTrail.AllowNew = false; auditTrail.AllowRemove = false; IList<AuditDataItemPersistent> rootItems = AuditDataItemPersistent.GetAuditTrail(ObjectSpace, this); if (rootItems != null) { foreach (AuditDataItemPersistent entry in rootItems) { auditTrail.Add(new CustomAuditDataItem(entry, "Contact")); } } foreach (MyTask task in MyTasks) { IList<AuditDataItemPersistent> taskItems = AuditDataItemPersistent.GetAuditTrail(ObjectSpace, task); if (taskItems != null) { foreach (AuditDataItemPersistent entry in taskItems) { auditTrail.Add(new CustomAuditDataItem(entry, "Task - " + task.Subject)); } } } } return auditTrail; } } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.