While doing a small AIF project I wrote a small batch class to cleanup the AIF document log because the button on the AifDocumentHistory form can take up a huge amount of time. The first thing I did to write this class is checking out the standard Ax code in the following method ClassesAifMessageManagerclearAllProcessedAndError. This method uses a progress bar and deletes records in batches of 3000 records, this is something we don’t need when running in batch.
The first thing our method needs to do is check if we have access rights to delete.
if ( !hasTableAccess(tablenum(AifMessageLog), AccessType::Delete) || !hasTableAccess(tablenum(AifDocumentLog), AccessType::Delete) || !hasTableAccess(tablenum(AifCorrelation), AccessType::Delete)) { throw error("@SYS113226"); } |
The second step is requesting the permission to skip AOS validation.
skipAOS = new SkipAOSValidationPermission(); skipAOS.assert(); |
The next step is calling all the skip methods, Microsoft does this to make sure that a delete_from doesn’t fall back to row by row deletes.
- skipAosValidation : Skips all validation methods (validateWrite, validateDelete, validateField)
- skipDatabaseLog : Prevents SQL from making transactions logs.
- skipDataMethods : Forces doInsert, doUpdate instead of insert, update.
- skipDeleteActions : Skips all actions defined under DeleteActions ( For example: Deleting a SalesTable also deletes all referencing MarkupTrans records. )
- skipDeleteMethod : Forces doDelete instead of delete.
- skipEvents : Disables a lot of kernel events to increase performance.
aifMessageLog.skipAosValidation(true); aifMessageLog.skipDatabaseLog(true); aifMessageLog.skipDataMethods(true); aifMessageLog.skipDeleteActions(true); aifMessageLog.skipDeleteMethod(true); aifMessageLog.skipEvents(true); aifDocumentLog.skipDatabaseLog(true); aifDocumentLog.skipDataMethods(true); aifDocumentLog.skipDeleteActions(true); aifDocumentLog.skipDeleteMethod(true); //BP Deviation Documented aifDocumentLog.skipAosValidation(true); aifDocumentLog.skipEvents(true); aifCorrelation.skipDatabaseLog(true); aifCorrelation.skipDataMethods(true); aifCorrelation.skipDeleteActions(true); aifCorrelation.skipDeleteMethod(true); //BP Deviation Documented aifCorrelation.skipAosValidation(true); aifCorrelation.skipEvents(true); |
After these methods we can start deleting the records, I’ve used a utcDateTimeRemove variable to cleanup records after a certain number of days.
delete_from aifDocumentLog exists join aifMessageLog where aifDocumentLog.MessageId == aifMessageLog.MessageId && aifMessageLog.createdDateTime <= utcDateTimeRemove && (aifMessageLog.Status == AifMessageStatus::Processed || aifMessageLog.Status == AifMessageStatus::Error); delete_from aifCorrelation exists join aifMessageLog where aifCorrelation.MessageId == aifMessageLog.MessageId && aifMessageLog.createdDateTime <= utcDateTimeRemove && (aifMessageLog.Status == AifMessageStatus::Processed || aifMessageLog.Status == AifMessageStatus::Error); delete_from aifMessageLog where aifMessageLog.createdDateTime <= utcDateTimeRemove && (aifMessageLog.Status == AifMessageStatus::Processed || aifMessageLog.Status == AifMessageStatus::Error); |
The final step is to revert the code access permission.
CodeAccessPermission::revertAssert(); |
Source : msdn xRecord class
(this job should never run on a production environment, build an archiving alternative instead)