Recently, our old (he is actually quite young - just has been using XAF for many years;-)) XAF customer, Nate, posted an interesting question at http://www.devexpress.com/issue=Q482829:
"Well, on my BO I want to replace four persistent fields UpdatedOn, UpdatedBy, CreatedOn, CreatedBy with non-persistent fields that pull this information from AuditTrail since it's already there and available. These values are to be shown on detail views so at a glance the user can get this info without going into the audit trail tab. I'm duplicating data by storing these values myself. However the concern is that audittrail is so large that querying this data will be too taxing on performance".
Indeed, how to avoid that duplication? While there is no unambiguous answer on whether this change will be worth from the performance point of view (it is not possible to predict whether the performance difference will be noticeable or not, because everything depends on the amount of history data, existence of indices and other factors), here is a solution to his requirement:
[PersistentAlias("[<AuditDataItemPersistent>][^.Oid=AuditedObject.GuidId].Max(ModifiedOn)")]
public DateTime ModifiedOn {
get {
return Convert.ToDateTime(EvaluateAlias("ModifiedOn"));
}
}
For testing purpuses I put this code into the Contact class in our MainDemo app.I find this solution interesting, because the criterion I used is quite tricky. Here I am using a cool XPO feature called Free Joins, because my Contact class has no direct relation to the audit data (yes, there is a ChangeHistory property in it, but it is not association).
Take special note that I am using ^. operator to refer to the Oid property of my Contact class (see here for more details on this syntax).
The AuditedObject is a property of the built-in AuditDataItemPersistent class used to store audit data. This property is of the AuditedObjectWeakReference type (a descendant of the XPO's XPWeakReference class) and has a few properties: GuidId, IntId and a string TargetKey one, inheriting from the base class. Take special note that my criterion assumes that the Contact's Oid key property is of the Guid type. So, if your business object has an integer key, then you would use the IntId property instead of the GuidId one in the criterion.
There is also a way to avoid this dependency on the key's type:
[PersistentAlias("[<AuditDataItemPersistent>][Contains(AuditedObject.TargetKey, ToStr(^.Oid))].Max(ModifiedOn)")]
public DateTime ModifiedOn {
get {
return Convert.ToDateTime(EvaluateAlias("ModifiedOn"));
}
}
Note that I had to use the Contais criteria function because the TargetKey is a string in a special format:
"Well, on my BO I want to replace four persistent fields UpdatedOn, UpdatedBy, CreatedOn, CreatedBy with non-persistent fields that pull this information from AuditTrail since it's already there and available. These values are to be shown on detail views so at a glance the user can get this info without going into the audit trail tab. I'm duplicating data by storing these values myself. However the concern is that audittrail is so large that querying this data will be too taxing on performance".
Indeed, how to avoid that duplication? While there is no unambiguous answer on whether this change will be worth from the performance point of view (it is not possible to predict whether the performance difference will be noticeable or not, because everything depends on the amount of history data, existence of indices and other factors), here is a solution to his requirement:
[PersistentAlias("[<AuditDataItemPersistent>][^.Oid=AuditedObject.GuidId].Max(ModifiedOn)")]
public DateTime ModifiedOn {
get {
return Convert.ToDateTime(EvaluateAlias("ModifiedOn"));
}
}
For testing purpuses I put this code into the Contact class in our MainDemo app.I find this solution interesting, because the criterion I used is quite tricky. Here I am using a cool XPO feature called Free Joins, because my Contact class has no direct relation to the audit data (yes, there is a ChangeHistory property in it, but it is not association).
Take special note that I am using ^. operator to refer to the Oid property of my Contact class (see here for more details on this syntax).
The AuditedObject is a property of the built-in AuditDataItemPersistent class used to store audit data. This property is of the AuditedObjectWeakReference type (a descendant of the XPO's XPWeakReference class) and has a few properties: GuidId, IntId and a string TargetKey one, inheriting from the base class. Take special note that my criterion assumes that the Contact's Oid key property is of the Guid type. So, if your business object has an integer key, then you would use the IntId property instead of the GuidId one in the criterion.
There is also a way to avoid this dependency on the key's type:
[PersistentAlias("[<AuditDataItemPersistent>][Contains(AuditedObject.TargetKey, ToStr(^.Oid))].Max(ModifiedOn)")]
public DateTime ModifiedOn {
get {
return Convert.ToDateTime(EvaluateAlias("ModifiedOn"));
}
}
Note that I had to use the Contais criteria function because the TargetKey is a string in a special format: