We came across the scenario where custom Auto Numbering plugin generates the duplicate numbers for an entity when two users create the records simultaneously. The reason behind this is because dynamics only locks a record inside a transaction if we update it. However what we are doing here is retrieving the record and then updating it. So effectively the record will be locked just at the end of the plugin execution which is not very helpful indeed.
Below are the steps to illustrate this:
1. First we are retrieving the config record which contains the prefix, last generated number and other details
2. Then we are reading the last updated number value and other config details
3. Then we are applying the logic to build the number
4. Finally, we are updating both the config(to maintain the last generated number) and the entity record in context with the required values.
So it is possible that two plugins is being executed and both those plugins performed step 1 above (so they both retrieved a config record). So they both will have the same value for the “Last Number” field. Then they will both apply the logic in step 2 and 3. Finally the first plugin will execute step 4 and update the config record (this will lock the config record) but it will finish execution immediately which will unlock the config record. So now the second plugin is executing step 4 but since it already has retrieved the old value so the update logic will be the same and it will override the config record with the same number instead of incrementing it.
So, we should update the logic in the plugin above to the following:
1. First, do a fake update to the required config record. We don’t have to change any values and we can just do service.update(configRecord);
2. Then we apply step 1, 2, 3 and 4 from the above logic.
Below is the sample code to show how to lock the configuration record:
I would like to thank my friend Shakarchi Ethra for describing this Dynamics behaviour.
Below are the steps to illustrate this:
1. First we are retrieving the config record which contains the prefix, last generated number and other details
2. Then we are reading the last updated number value and other config details
3. Then we are applying the logic to build the number
4. Finally, we are updating both the config(to maintain the last generated number) and the entity record in context with the required values.
So it is possible that two plugins is being executed and both those plugins performed step 1 above (so they both retrieved a config record). So they both will have the same value for the “Last Number” field. Then they will both apply the logic in step 2 and 3. Finally the first plugin will execute step 4 and update the config record (this will lock the config record) but it will finish execution immediately which will unlock the config record. So now the second plugin is executing step 4 but since it already has retrieved the old value so the update logic will be the same and it will override the config record with the same number instead of incrementing it.
So, we should update the logic in the plugin above to the following:
1. First, do a fake update to the required config record. We don’t have to change any values and we can just do service.update(configRecord);
2. Then we apply step 1, 2, 3 and 4 from the above logic.
Below is the sample code to show how to lock the configuration record:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // Get the record for which Auto Number to be generated Entity targetEntityRecord = (Entity)context.InputParameters["Target"]; // Fetch the configuration record Entity configRecord = GetConfigurationRecord(service); // If configuration record found, then do a fake update if (configRecord.Id != Guid.Empty) service.Update(configRecord); else throw new InvalidPluginExecutionException("Config record not found."); // Get the last generated number from configuration record int lastNumber = Int32.Parse(configRecord.Attributes["new_lastnumber"].ToString()); // Increment the last generated number lastNumber++; // Build a number with your own logic string autoNumber = string.Format("{0}-{1}", "PREFIX" , lastNumber); // Set new generated number to both target entity and Configuration record targetEntityRecord.Attributes.Add("new_name", autoNumber); configRecord.Attributes["new_lastnumber"] = lastNumber; // Update the Configuration record service.Update(configRecord); |
I would like to thank my friend Shakarchi Ethra for describing this Dynamics behaviour.
Thank you so much Charan and Shakarchi
ReplyDeleteThis worked really well
You're welcome my friend. It's my pleasure. :)
DeleteTechnical Treatment: Auto Number: Record Locking In Mscrm Plugin >>>>> Download Now
Delete>>>>> Download Full
Technical Treatment: Auto Number: Record Locking In Mscrm Plugin >>>>> Download LINK
>>>>> Download Now
Technical Treatment: Auto Number: Record Locking In Mscrm Plugin >>>>> Download Full
>>>>> Download LINK nB
Hi,
ReplyDeleteGlad I found your site, this is an eye-opener for marketers. We are proud to be a solution provider for a diversified customer database, ranging from the small, medium technology firms to the giant multinationals. Generate more revenue with email marketing, b2b marketing, list solutions & market research services. Microsoft Dynamics CRM Users Email List
Thanks for your post. It's good idea. But I have do the same. When I test, still generated duplicated ID. Have an other way to solve this problem!!!
ReplyDeleteOne issue here is that after updating, you have to retrieve the record again, in case another user updated the record between your initial retrieve and first update. If another user updates the record before you, your dummy update will "wait" until it's available.
ReplyDeleteCorrect sequence:
search for and retrieve record, save the number into a variable
do the dummy update
retrieve record again, check that record number and saved number are the same. If that's the case, you have the lock and can proceed.
If not, use the new number and proceed.
More straight-forward, don't bother checking the record, you always know it's going to be locked after you update, so just retrieve and carry on.
This is still susceptible to deadlock if one gets a read lock and the other gets a write lock, but it's much less likely. To avoid that, put the ID of the config record into a configuration (either plugin configuration or a web resource) so you don't have to retrieve it first, just update and then retrieve.
Hi Michael,
DeleteThank you for your valuable suggestion. :)
didn't work for me.. I am using D365 On-premise, also have the alternate key
ReplyDeletebut when trying to bomb it with multiple threads it gets duplicates
This article gives the light in which we can observe the reality. Wellington towing service I like this kind of blog. Thanks for sharing informative information with us
ReplyDeleteTechnical Treatment: Auto Number: Record Locking In Mscrm Plugin >>>>> Download Now
ReplyDelete>>>>> Download Full
Technical Treatment: Auto Number: Record Locking In Mscrm Plugin >>>>> Download LINK
>>>>> Download Now
Technical Treatment: Auto Number: Record Locking In Mscrm Plugin >>>>> Download Full
>>>>> Download LINK Vf