/// <summary> /// An extension class of the <c>InventUpd_Registered</c> class. /// </summary> [ExtensionOf(classStr(InventUpd_Registered))] final class VKInventUpd_RegisteredCls_Extension { /// <summary> /// CoC extension of the updateNow() method /// </summary> public void updateNow() { using(VKUpdateConflictInventTransContext context = VKUpdateConflictInventTransContext::construct()) { next updateNow(); } } }
/// <summary> /// CoC extension for InventTrans table /// </summary> [ExtensionOf(tableStr(InventTrans))] final class VKInventTransTbl_Extension { public void update( NoYes _dropInventOnHand, NoYes _canDropInventSumDelta, InventDimId _inventDimIdTransferIssue) { next update(_dropInventOnHand, _canDropInventSumDelta, _inventDimIdTransferIssue); VKUpdateConflictInventTransContext context = VKUpdateConflictInventTransContext::current(); if (context) { context.recordUpdated(this); } } /// <summary> /// CoC for findByInventTransOrigin method /// </summary> /// <param name = "_inventTransOriginId">InventTransOriginId</param> /// <param name = "_forUpdate">boolean</param> /// <returns>InventTrans</returns> public static InventTrans findByInventTransOrigin( InventTransOriginId _inventTransOriginId, boolean _forUpdate) { InventTrans inventTrans = next findByInventTransOrigin(_inventTransOriginId, _forUpdate); if (_forUpdate) { VKUpdateConflictInventTransContext context = VKUpdateConflictInventTransContext::current(); if (context) { context.recordSelectedForUpdate(inventTrans); } } return inventTrans; } /// <summary> /// CoC for findRecId method /// </summary> /// <param name = "_recId">RecId</param> /// <param name = "_forUpdate">boolean</param> /// <returns>InventTrans</returns> public static InventTrans findRecId( RecId _recId, boolean _forUpdate) { InventTrans inventTrans = next findRecId(_recId, _forUpdate); if (_forUpdate) { VKUpdateConflictInventTransContext context = VKUpdateConflictInventTransContext::current(); if (context) { context.recordSelectedForUpdate(inventTrans); } } return inventTrans; } /// <summary> /// CoC for updateSumUp method /// </summary> /// <param name = "_always">NoYes</param> /// <param name = "_disableCacheForBufferCheck">boolean</param> /// <param name = "_deletedTransactions">Set</param> public void updateSumUp(NoYes _always, boolean _disableCacheForBufferCheck, Set _deletedTransactions) { VKUpdateConflictInventTransContext context = VKUpdateConflictInventTransContext::current(); if (context) { if (context.shouldReread(this)) { this.reread(); } } next updateSumUp(_always, _disableCacheForBufferCheck, _deletedTransactions); } }3. General class with common logic to resolve update conflicts
/// <summary> /// The class provides common logic to resolve table conflicts using context (isolated cases) /// </summary> abstract class VKUpdateConflictCommon implements System.IDisposable { protected Map recVersionMap; protected void new() { recVersionMap = new Map(Types::Int64, Types::Int64); } /// <summary> /// Should be called when record is selected forUpdate /// </summary> /// <param name = "_record">Record</param> public void recordSelectedForUpdate(common _record) { if (recVersionMap.exists(_record.RecId)) { recVersionMap.remove(_record.RecId); } recVersionMap.insert(_record.RecId, _record.RecVersion); } /// <summary> /// Should be called when record is updated (after super) /// </summary> /// <param name = "_record">Record</param> public void recordUpdated(common _record) { this.recordSelectedForUpdate(_record); } /// <summary> /// Call before record update to understand if there will be update conflict /// </summary> /// <param name = "_record">Record</param> /// <returns>Boolean</returns> public boolean shouldReread(common _record) { boolean ret = false; if (recVersionMap.exists(_record.RecId) && _record.RecVersion != recVersionMap.lookup(_record.RecId)) { ret = true; } return ret; } /// <summary> /// Safely reread table buffer in case it has been updated to avoid update conflict. /// </summary> /// <param name = "_record">Table buffer record.</param> public static void safeReread(Common _record) { Common record = _record; Common recordOrig = _record.orig(); DictTable dictTable = new DictTable(_record.TableId); DictField dictField; // Compare a source record with its original buffer to collect FieldId/Value pairs for updated fields. Map updatedFieldsMap = new Map(Types::Integer, Types::Container); for (int i = 1; i <= dictTable.fieldCnt(); i++) { dictField = new DictField(record.TableId, dictTable.fieldCnt2Id(i)); if (!isSysId(dictField.id()) && record.(dictField.id()) != recordOrig.(dictField.id())) { updatedFieldsMap.add(dictField.id(), [record.(dictField.id())]); } } // Reread a source record record.reread(); // Apply previously collected field values. if (updatedFieldsMap.elements() > 0) { MapEnumerator updatedFieldsMapEnum = updatedFieldsMap.getEnumerator(); while (updatedFieldsMapEnum.moveNext()) { if ([record.(updatedFieldsMapEnum.currentKey())] != updatedFieldsMapEnum.currentValue()) { [record.(updatedFieldsMapEnum.currentKey())] = updatedFieldsMapEnum.currentValue(); } } } } abstract public void dispose() { } }
/// <summary> /// InventTrans record update conflict context /// </summary> public class VKUpdateConflictInventTransContext extends VKUpdateConflictCommon { static VKUpdateConflictInventTransContext instance; protected void new() { if(instance) { // Nesting of %1 is not supported throw error(strFmt("@WAX:NestingOfContextIsNotSupportedWarning", classStr(VKUpdateConflictInventTransContext))); } instance = this; super(); } static public VKUpdateConflictInventTransContext construct() { VKUpdateConflictInventTransContext ret = VKUpdateConflictInventTransContext::current(); if (!ret) { ret = new VKUpdateConflictInventTransContext(); } return ret; } public void dispose() { instance = null; } /// <summary> /// Get the context if exists /// </summary> /// <returns>VKUpdateConflictInventTransContext</returns> static public VKUpdateConflictInventTransContext current() { return instance; } }
If you found value in what I share, I've set up a Buy Me a Coffee page as a way to show your support.
Buy Me a CoffeeNo comments. Be the first one to comment on this post.
DaxOnline.org is free platform that allows you to quickly store and reuse snippets, notes, articles related to Dynamics AX.
Authors are allowed to set their own "buy me a coffee" link.
Join us.