Answered by:
Update picklist via workflow from related record

Question
-
I need to update picklist value from one entity to another via workflow. Normally, I would create a bunch of IF conditions which works OK for a small list, however, this picklist is a list of 50 states. Anyone got any ideas on how best to handle this via workflow?
Thanks
AppsMonday, October 25, 2010 6:41 PM
Answers
-
Ok, since my last chime in on this situation, it appears I misinterpreted the initial desire. You appear to be desiring a forced synchronization between two Picklists across different entities. What I don't see is a description from you about how these two entities are related to each other. Please explain the relationships between the two entities, so that the best model for your synchronization can be recommended.
Also, Workflows work asynchronously. If you rely on Workflows to keep the values up to date, there will be a delay between when the value on record A is changed and when the change appears on record B. This delay can be exacerbated by various performance factors regarding the Asynchronous Processing service (e.g. the number of jobs currently awaiting execution, the size of the Async Job table, etc.). Additionally, if you're not cleaning out completed Workflows, you're arbitrarily and unnecessarily increasing the size of the Async Job table, which could impact SQL performance for your whole CRM deployment.
My recommendation in these scenarios is to rely on Plug-ins, hooked into the "Create" and "Update" messages, to force the synchronization. Then, it's only a matter of traversing the relationship between your records to copy the desired value into the target.
Dave Berry - MVP Dynamics CRM - http:\\crmentropy.blogspot.com- Marked as answer by DavidBerryMVP, Moderator Friday, November 5, 2010 7:08 PM
Thursday, October 28, 2010 7:55 PMModerator -
Your best bet is probably to set the picklist value in a plugin; register for "Create" message on the child entity, lookup the parent record and update correspondingly. Requires coding, but would be rather trivial.
--pogo (pat)- Proposed as answer by DavidBerryMVP, Moderator Wednesday, November 3, 2010 4:38 AM
- Marked as answer by DavidBerryMVP, Moderator Friday, November 5, 2010 7:09 PM
Tuesday, October 26, 2010 10:51 PM -
Fine.
1. Do a mapping it will work on create of child record.
2. Download http://crm40distributewf.codeplex.com/releases/view/40867 and register the dll file. From the guide you can easily configure the workflow to update child entity picklist on change of parent entity picklist.
OR
1. Configure the java script as suggested above. It will only work when user opens the form and do create/update and will not work with data import or update using web services.
OR
Plugin.
Regards
Faisal
- Marked as answer by DavidBerryMVP, Moderator Friday, November 5, 2010 7:08 PM
Friday, October 29, 2010 10:00 AM
All replies
-
Never figured this one out: seems like it would be often needed. You can use a referential relationship mapped fields or JavascriptTuesday, October 26, 2010 6:11 AM
-
How/where would I use javascript?
Again, we have an entity with a picklist and child entity with a corresponding picklist and plan to create the child record via workflow and set the picklist value on the child to be the same as the parent record. In the Set Properties view of the form in the workflow editor the picklist on the record we were creating does not have the dynamic values in the right hand screen as expected. I could, conceivably, create 50 if statements but there just has to be an easier way in a workflow to do this.
thanks
Tuesday, October 26, 2010 11:16 AM -
Your best bet is probably to set the picklist value in a plugin; register for "Create" message on the child entity, lookup the parent record and update correspondingly. Requires coding, but would be rather trivial.
--pogo (pat)- Proposed as answer by DavidBerryMVP, Moderator Wednesday, November 3, 2010 4:38 AM
- Marked as answer by DavidBerryMVP, Moderator Friday, November 5, 2010 7:09 PM
Tuesday, October 26, 2010 10:51 PM -
Easy for you to say.... :) but it sounds complicated to me since I am unfamiliar with how to create a plug-in, register for Create message, etc.
Thanks
AppsWednesday, October 27, 2010 4:55 PM -
Why not export the data for both entities to Excel, and copy the data into the blank fields on the target entity (so long as you have reasonably matched the rows to your specifications), and then use the Data Import feature? Also, the Bulk Update and Export tool can help, but you still need to find away to map records between the exported entities to each other--you could use Access or Excel for that, I imagine.
Dave Berry - MVP Dynamics CRM - http:\\crmentropy.blogspot.comWednesday, October 27, 2010 5:08 PMModerator -
/*
Installation:
Add this script to onLoad event of the child entity.Description:
This method will set the Geographic State of child activity(SHC) based on the Opportunity.*/
// state of SHC
SetState();// state of SHC function SetState()
function SetState()
{
var StateField = document.crmForm.all.ssa_state;
if (StateField.DataValue == null)
{
var opportunity= new Array();
opportunity = null;
opportunity = crmForm.all.regardingobjectid.DataValue;
//alert (opportunity[0].name);
//alert (opportunity[0].id);if (opportunity!= null)
{
var opportunityid =opportunity[0].id;
var typeName = opportunity[0].typename;var State = GetState(opportunityid, typeName);
if (State != null)
{
StateField.DataValue = State;
}
}
}
}// Method to find the a state for a record
function GetState(opportunityid, typeName)
{
// Define URL to CRM API service
var serverUrl = "/MSCrmServices/2007/CrmService.asmx";// Set up XMLHTTP request
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.open("POST", serverUrl, false);
xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8")// Specify correct SOAP action in the header
xmlhttp.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/Retrieve")// Define the retrieve message
var message =
[
"<?xml version='1.0' encoding='utf-8'?>",
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">",
GenerateAuthenticationHeader(),
"<soap:Body>",
"<Retrieve xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>",
"<entityName>",
typeName,
"</entityName>",
"<id>",
opportunityid,
"</id>",
"<columnSet xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:ColumnSet'>",
"<q1:Attributes><q1:Attribute>ssa_statelist</q1:Attribute></q1:Attributes>",
"</columnSet>",
"</Retrieve>",
"</soap:Body>",
"</soap:Envelope>"
].join("");// Submit to the CRM API web service and receive a response
xmlhttp.send(message);
var result = xmlhttp.responseXML.xml;// Create a new DOM document and load the response XML
var doc = new ActiveXObject("MSXML2.DOMDocument");
doc.async = false;
doc.loadXML(result);// Return the q1:ssa_statelist node
var statelistNode = doc.selectSingleNode("//q1:ssa_statelist");
if( statelistNode != null )
{
// If the node exists, return its value
return statelistNode.text;
}
else
{
return null;
}
}Thursday, October 28, 2010 1:18 AM -
Thanks for your responses...I am now confused. Are you saying that I have to put all of this code in the child entity simply to enable the Set Properties view of the form in the workflow editor to show the appropriate state in the picklist?
AppsThursday, October 28, 2010 10:59 AM -
Hi Bernardina,
Create both the picklist exactly with same value. You can do this by
1. Creating them manually.
2. Create picklist attribute with values on any say 1st entity. Create picklist attribute on the 2nd entity. Now export customization of first entity and copy all the options of picklist( it's fetchXml). Open the customization of 2nd entity and paste all options under the attibute which you have created for picklist. Save it, import it and publish it.
Now both the picklist are exactly same. No to keep the in sync you can use any of the following methods.
1. Off the shelf workflow will update from child entity to parent entity. For updating from parent to child you need to use http://crm40distributewf.codeplex.com/releases/view/40867 but you will run into bigger issue of loop there use javacript for update from child to parent and crm40distributeWF for parent to childs.
2. You can use service.update from the sdk (bothways)
3. Do a mapping it will work on create.
4. Plugin
Regards
Faisal
Thursday, October 28, 2010 4:15 PM -
Both picklists have exactly the same value for the states already.
AppsThursday, October 28, 2010 5:09 PM -
You want a one way update or two way update?
Thursday, October 28, 2010 5:15 PM -
One way. I just want to update the child record that will be created from the workflow. Sorry. I am new to this and trying to understand the logic behind some of the valuable answers given. Just struggling. Thanks
AppsThursday, October 28, 2010 5:28 PM -
Ok, since my last chime in on this situation, it appears I misinterpreted the initial desire. You appear to be desiring a forced synchronization between two Picklists across different entities. What I don't see is a description from you about how these two entities are related to each other. Please explain the relationships between the two entities, so that the best model for your synchronization can be recommended.
Also, Workflows work asynchronously. If you rely on Workflows to keep the values up to date, there will be a delay between when the value on record A is changed and when the change appears on record B. This delay can be exacerbated by various performance factors regarding the Asynchronous Processing service (e.g. the number of jobs currently awaiting execution, the size of the Async Job table, etc.). Additionally, if you're not cleaning out completed Workflows, you're arbitrarily and unnecessarily increasing the size of the Async Job table, which could impact SQL performance for your whole CRM deployment.
My recommendation in these scenarios is to rely on Plug-ins, hooked into the "Create" and "Update" messages, to force the synchronization. Then, it's only a matter of traversing the relationship between your records to copy the desired value into the target.
Dave Berry - MVP Dynamics CRM - http:\\crmentropy.blogspot.com- Marked as answer by DavidBerryMVP, Moderator Friday, November 5, 2010 7:08 PM
Thursday, October 28, 2010 7:55 PMModerator -
I don't think any relationship mapped fields update when the record is created from a workflow, as he mentions he's doing. When I did the same thing the child picklist field will not show parent picklists to choose in the dynamic values. One other option which sucks for reporting is with the workflow you can put a parent picklist value into a child nvarchar...
Yes, Bernardina
the script I pasted all goes in the child onLoad. I used it to populate an activity geographic state picklist from the parent opportunity because of timezone issues when our national call center creates appoinments in other states as the contacts don't have a timezone recorded.
Thursday, October 28, 2010 11:49 PM -
Fine.
1. Do a mapping it will work on create of child record.
2. Download http://crm40distributewf.codeplex.com/releases/view/40867 and register the dll file. From the guide you can easily configure the workflow to update child entity picklist on change of parent entity picklist.
OR
1. Configure the java script as suggested above. It will only work when user opens the form and do create/update and will not work with data import or update using web services.
OR
Plugin.
Regards
Faisal
- Marked as answer by DavidBerryMVP, Moderator Friday, November 5, 2010 7:08 PM
Friday, October 29, 2010 10:00 AM -
Adi Katz, the CRM wizard at Global Interface, has an awesome ISV solution for mapping .
Dave Berry - MVP Dynamics CRM - http:\\crmentropy.blogspot.comFriday, November 5, 2010 7:11 PMModerator -
thanks for response. My initial desire
3 entities - Contracts / Client / Account. They all have relationships (contacts has a N:1 to client/account) (account has mapped address fields to client so that when a client record is created directly from the account record, the address info shows on the client record).
Using a workflow....from the Contracts entity, if a field is checked, create a new Client (related) record, which contains an address section that picks up state (picklist) field from the (related) Account entity.
Apparently, picklist values must be set specifically (can't be dynamically updated) on a workflow. Therefore, your suggestion is to create a 'plug in' of state values? Is this correct?
Appreciate everyone's feedback.
AppsSunday, November 7, 2010 3:04 PM -
If you require the values to be synchronized constantly between the records--at all times--I do recommend a Plug-In. It's simple, efficient, and synchronous. If the value should only be equated when a new record is established, then establishing a mapping on the relationship between the records is the best bet.
One question, though: when you say "state", do you mean the natural State and Status of the record (e.g. "Active", "Inactive"), or are you talking about a geophysical location ("Washington", "California")?
Dave Berry - MVP Dynamics CRM - http:\\crmentropy.blogspot.comMonday, November 8, 2010 4:19 AMModerator -
The value should only be equated when a new record is established.
Currently, the State (TN, AZ, etc.) gets populated when a client record is created directly from the account record. However, the State field needs to be populated when this specific workflow creates a new related (Client) record, as well. Because it is a picklist, no dynamic value shows up in the 'Look For' section. I don't understand why.
AppsMonday, November 8, 2010 11:52 AM -
I assume that behavior is by design, since it would be a huge assumption and leap of faith for the Workflow engine to believe that any two picklists were identical, since in most cases they are not. Unfortunately, creating the Client record from a Workflow means that there is no ordinal relationship vector that the system can use as a reference for automatic mapping operations--therefore, a Create-based Plug-In (on the Client record) may be the best, and easiest way to move forward. The nice thing, is that since you don't need to force the values to be synchronized at all times, you don't need to push an Update-based Plug-In to either the Client or Account records.
Dave Berry - MVP Dynamics CRM - http:\\crmentropy.blogspot.comMonday, November 8, 2010 8:14 PMModerator -
I understand. Can you tell me where I can find a sample of the create-based plug-in so that I can replace my attribute names, etc. Someone must have encountered this problem before. And, I have never created a plug-in from scratch.
Thank you
AppsTuesday, November 9, 2010 11:49 AM -
If you provide me with the schema names of your entities and "state" attributes, I can give you a simple tutorial and code example.
Dave Berry - MVP Dynamics CRM - http:\\crmentropy.blogspot.comTuesday, November 9, 2010 8:58 PMModerator -
That would help me. I need to learn how to do this.
account
address1_stateorprovince2client
address1_stateorprovinceThank you
AppsWednesday, November 10, 2010 12:00 PM -
Since the entities and attributes you reference, aside from "account", do not exist in vanilla CRM, I'm going to assume that you forgot the prefix to the schema names. By default, this is "new_". If you have changed yours, then the code I've written for you will need to be changed to match the complete schema names you have in use. Here's the code for a single-file project that will allow you to map the attributes upon creation of a new client record:
using System; using System.Collections.Generic; using System.Text; using System.Web.Services; using Microsoft.Crm.Sdk; using Microsoft.Crm.SdkTypeProxy; namespace AttributeMappings { public class ToClientFromAccount : IPlugin { public void Execute(IPluginExecutionContext context) { // Check the InputParameters for a Target that represents the newly created "client" record if (context.InputParameters.Properties.Contains("Target") && context.InputParameters.Properties["Target"] is DynamicEntity) { // Establish a reference to the Target DynamicEntity client = (DynamicEntity)context.InputParameters.Properties["Target"]; // Abandon any further code if no relationship to an Account is discovered if (!client.Properties.Contains("new_accountid")) return; // Establish a reference to the Account's primary key Lookup parentAccountId = (Lookup)client.Properties["new_accountid"]; // Create a new CRM Service object to query data from the Account ICrmService crmService = context.CreateCrmService(false); // Retrieve state information from the account TargetRetrieveDynamic target = new TargetRetrieveDynamic(); target.EntityId = parentAccountId.Value; target.EntityName = EntityName.account.ToString(); RetrieveRequest retrieve = new RetrieveRequest(); retrieve.ColumnSet = new ColumnSet(new string[] {"new_address1_stateorprovince2"}); retrieve.ReturnDynamicEntities = true; retrieve.Target = target; RetrieveResponse retrieved = (RetrieveResponse)crmService.Execute(retrieve); // Abandon any further code if no DynamicEntity was returned if (!retrieved.BusinessEntity is DynamicEntity) return; DynamicEntity parentAccount = (DynamicEntity)retrieved.BusinessEntity; // If the "new_address1_stateorprovince2" property was returned (meaning that it's not null), load it into the Client reference for creation if (parentAccount.Properties.Contains("new_address1_stateorprovince2") { Picklist accountState = (Picklist)parentAccount.Properties["new_address1_stateorprovince2"]; client.Properties.Add(new PicklistProperty("new_address1_stateorprovince", accountState)); } } } } }
This code will need to be compiled with the references to the SDK's DLLs (microsoft.crm.sdk.dll , and microsoft.crm.sdktypeproxy.dll ), and registered to CRM on the Create message for the "Client" entity, in the "Pre" stage of the "Parent" pipeline.
Dave Berry - MVP Dynamics CRM - http:\\crmentropy.blogspot.comWednesday, November 10, 2010 6:19 PMModerator -
I purposely left off the prefix to the schema name. I figured that I would have to revise accordingly. Thanks. I will read the info and try it. Thank you
AppsWednesday, November 10, 2010 6:24 PM