Microsoft Dynamics CRM 2016插件开发:更新账户地址同步联系人地址
Hey there, I’ve worked with Dynamics CRM 2016 on-prem quite a bit, so I know exactly how tricky this address sync can be since addresses live in their own customeraddress entities. Let’s walk through a working code snippet that’ll do exactly what you need—syncing the updated account address to all linked contacts.
Key Background
In CRM, account and contact addresses are stored as separate customeraddress records, linked via lookup fields (like billtoaddressid for billing addresses, shiptoaddressid for shipping). When you update an account’s address, CRM updates the associated customeraddress record and updates the account’s lookup field to point to that updated address. Our job is to copy that lookup reference to all linked contacts.
Full Plugin Code Snippet
Here’s the complete code for your Execute method, with comments explaining each step:
using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; using System; using System.Collections.Generic; public class SyncAccountAddressToContacts : IPlugin { public void Execute(IServiceProvider serviceProvider) { // Grab core CRM services from the provider IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); try { // Only run for Account Update operations if (context.MessageName != "Update" || context.PrimaryEntityName != "account") return; // Get the updated account record from the plugin context Entity updatedAccount = (Entity)context.InputParameters["Target"]; // Target the billing address here - swap with shiptoaddressid if syncing shipping addresses Guid? accountAddressId = updatedAccount.GetAttributeValue<EntityReference>("billtoaddressid")?.Id; // Skip if no address was set on the account if (!accountAddressId.HasValue) return; // Query all contacts linked to this account QueryExpression contactQuery = new QueryExpression("contact") { ColumnSet = new ColumnSet("contactid", "billtoaddressid"), // Only fetch needed fields Criteria = new FilterExpression { Conditions = { new ConditionExpression("parentcustomerid", ConditionOperator.Equal, context.PrimaryEntityId) } } }; EntityCollection relatedContacts = service.RetrieveMultiple(contactQuery); if (relatedContacts.Entities.Count == 0) return; // Prepare contacts for update (skip if address is already matching) List<Entity> contactsToUpdate = new List<Entity>(); foreach (Entity contact in relatedContacts.Entities) { Guid? currentContactAddressId = contact.GetAttributeValue<EntityReference>("billtoaddressid")?.Id; if (currentContactAddressId != accountAddressId) { Entity contactUpdate = new Entity("contact", contact.Id); contactUpdate["billtoaddressid"] = new EntityReference("customeraddress", accountAddressId.Value); contactsToUpdate.Add(contactUpdate); } } // Batch update for efficiency (critical if you have many contacts) if (contactsToUpdate.Count > 0) { ExecuteMultipleRequest batchRequest = new ExecuteMultipleRequest { Settings = new ExecuteMultipleSettings { ContinueOnError = false, ReturnResponses = false }, Requests = new OrganizationRequestCollection() }; foreach (Entity contact in contactsToUpdate) { batchRequest.Requests.Add(new UpdateRequest { Target = contact }); } service.Execute(batchRequest); } } catch (Exception ex) { // Throw a meaningful error for debugging throw new InvalidPluginExecutionException($"Failed to sync account address to contacts: {ex.Message}", ex); } } }
Important Setup Notes
- Plugin Registration: Register this plugin on the
accountentity’sUpdatemessage. Set Filtering Attributes tobilltoaddressid(orshiptoaddressidif syncing shipping addresses) so it only runs when the address is actually changed. - Permissions: Ensure the plugin’s execution user has:
- Read/Write access to
accountandcontactentities - Read access to
customeraddressentities
- Read/Write access to
- Address Type: To sync shipping addresses instead, replace all instances of
billtoaddressidwithshiptoaddressidin the code. - Batch Updates: Using
ExecuteMultipleRequestis far more efficient than individualUpdateRequestcalls, especially if the account has dozens/hundreds of linked contacts.
内容的提问来源于stack exchange,提问作者Mike Bradley

