Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attribute Change Management #27

Open
bo-stig-christensen opened this issue Nov 28, 2019 · 0 comments
Open

Attribute Change Management #27

bo-stig-christensen opened this issue Nov 28, 2019 · 0 comments

Comments

@bo-stig-christensen
Copy link
Member

The Problem
Currently we need to write explicit code to handle updating only changed attributes on an entity. Some developers do it, others take the easy way out and doesn't. - This results in audit log and potentially performance suffering with attributes being updated that do not need to, which in turn also may trigger additional plugins and flows unintentionally.
An example of current necessary code to detect changes and update 3 attributes:

var newActualValue = 22222;
var newActualCloseDate = DateTime.Now;
var newBudgetAmount = 12345;
var opportunityFromD365 = Opportunity.Retrieve(OrganizationService, opportunityId);

var updOpportunity = new Opportunity(opportunityId);
if (opportunityFromD365.ActualValue != newActualValue)
    updOpportunity.ActualValue = newActualValue;
if (opportunityFromD365.ActualCloseDate != newActualCloseDate)
    updOpportunity.ActualCloseDate = newActualCloseDate;
if (opportunityFromD365.BudgetAmount != newBudgetAmount)
    updOpportunity.BudgetAmount = newBudgetAmount;

OrganizationAdminService.Update(updOpportunity);

Much of the time, what I see is that a standard object initializer is used instead and no explicit check for changed attribute values are added.

The Solution
It would be nice to be able to write the following code instead:

var newActualValue = 22222;
var newActualCloseDate = DateTime.Now;
var newBudgetAmount = 12345;
var opportunity = Opportunity.Retrieve(OrganizationService, opportunityId);
opportunity.ActualValue = newActualValue;
opportunity.ActualCloseDate = newActualCloseDate;
opportunity.BudgetAmount = newBudgetAmount;
opportunity.Update(OrganizationService);

In this case I would expect the following from the generated entity classes:

  1. An internal "ChangedAttributes" field, which is maintained by Property Setter implementation on each attribute's property.
  2. An internal "OriginalAttributes" field, which contains the initial values fetched from D365.
  3. Each attribute property must have a setter that compares the set value with the original value from D365 and updates the ChangedAttributes collection accordingly (adds or removes item).
  4. A Public GetChangedEntity() method that returns an entity instance with only the changed attributes (based on ChangedAttributes collection, not a D365 call).
  5. A Public Update() method that basically uses GetChangedEntity() and calls the service.Update() method as well as doing some housekeeping like clearing the ChangedAttributes collection.

Another potential strategy could be to optionally allow the entity.Update() method to retrieve the entity fresh from D365 based on a method parameter, extrapolate the changedEntity and run an update. - However, this strategy will generate an additional API call, which may not always be what we want due to limits and performance ;-)

Key benefits

  1. Avoid Audit Log spamming with Old and New values being the same.
  2. Avoid plugins, workflows and flows triggering unintentionally.
  3. Slightly less boilerplate code each time we update an entity.
  4. Move responsibility of implementing clean updates from developer to framework, which will minimize issues related to developer error and/or laziness, with a possibility to explicitly override if needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant