Creating Complex Records in Dynamics CRM 2011 from BizTalk Server 2010

A little while back I did a blog post that showed how to query and create Dynamics CRM 2011 records from BizTalk Server.  This post will demonstrate how to handle more complex scenarios including creating fields that use option sets (list of values) or entity references (fields that point to another record).

To start with, my Dynamics CRM environment has an entity called Contact which represents a person that the CRM system has interacted with.  The Contact entity has fields to hold basic demographics and the like.  For this demonstration, the Address Type is set to an option set (e.g. Home, Work, Hospital, Temporary).  Notice that an option set entry has both a name and value.  FYI, custom option set entries apparently use a large prefix number which is why my value for “Home” is 929,280,003.

2011.5.20crm01

The State is a lookup to another entity which holds details about a particular US state.  This could have been an option set as well, but in this case, it’s an entity.

2011.5.20crm02

With that information out of the way, we can now jump into our integration solution.  Within a BizTalk Server 2010 project, I’ve added a Generated Item which consumed the Organization SOAP service exposed by Dynamics CRM 2011.  This brought in a host of things of which I deleted virtually all of them.  The CRM 2011 SDK has an "Integration” folder which has valid schemas that BizTalk can use.  The schemas generated by the service reference are useless.  So why add the service reference at all?  I like getting the binding file that we can later use to generate the BizTalk send port that communicates with Dynamics CRM 2011.

Next up, I created a new XSD schema which represented the customer record coming into BizTalk Server.  This is a simple message that has some basic demographic details.  One key thing to notice is that both the AddressType and State elements are XSD records (of simple type, so they can hold text) with attributes.  The attribute values will hold the identifiers that Dynamics CRM needs to create the record for the contact.

2011.5.20crm04

Now comes the meat of the solution: the map.  I am NOT using an orchestration in this example.  You certainly could, and in real life, you might want to.  In this case, I have a messaging only solution.  The first thing that my map does is connect each of the source nodes to a Looping functoid which in turn connects to the repeating node (KeyValuePairOfstringanyType) in the destination Create schema.  This ensures that we create one of these destination nodes for each source node.

2011.5.20crm05

On the next map page, I’m using Scripting functoids to properly define the key/value pairs underneath the KeyValuePairOfstringanyType node.  For instance, the source node named First under the Name record maps to a Scripting functoid that has the following Inline XSLT Call Template set:

<xsl:template name="SetFNameValue">
<xsl:param name="param1" />
<key 
 xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
  firstname</key>
<value 
 xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic" 
 xmlns:xs="http://www.w3.org/2001/XMLSchema" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <xsl:attribute name="xsi:type">
     <xsl:value-of select="'xs:string'" />
   </xsl:attribute>
   <xsl:value-of select="$param1" />
  </value>

</xsl:template>

Notice there that I am “typing” the value node to be a xs:string.  This is the same script used for the Middle, Last, Street1, City, and Zip nodes.  They are all simple string values.  As you may recall, the AddressType is an option set.  If I simply pass its value as a xs:string, nothing actually gets added on the record.  If I try and send in a node on the FormattedValues node (which when querying, pulls back friendly names of option set values), nothing happens.  From what I can tell, the only way to set the value of an option set field is to send in the value associated with the option set entry.

In this case, I connect the TypeId node to the Scripting functoid and have the following Inline XSLT Call Template set:

<xsl:template name="SetAddrTypeValue">
<xsl:param name="param1" />
<key xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
   address2_addresstypecode</key>
<value 
  xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">
   <xsl:attribute name="xsi:type">
    <xsl:value-of select="'a:OptionSetValue'" />
   </xsl:attribute>
   <Value xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
       <xsl:value-of select="$param1" />
   </Value>
  </value>
</xsl:template>

A few things to point out.  First, notice that the “type” of my value node is an OptionSetValue.  Also see that this value node contains ANOTHER Value node (notice capitalization difference) which holds the numerical value associated with the option set entry.

The last node to map is the StateId from the source schema through a Scripting functoid with the following Inline XSLT Call Template:

<xsl:template name="SetStateValue">
<xsl:param name="param1" />
<key xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
    address2stateorprovinceid</key>
<value xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic" 
         xmlns:xs="http://www.w3.org/2001/XMLSchema" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">
   <xsl:attribute name="xsi:type">
    <xsl:value-of select="'a:EntityReference'" />
   </xsl:attribute>
   <Id xmlns="http://schemas.microsoft.com/xrm/2011/Contracts" 
        xmlns:ser="http://schemas.microsoft.com/2003/10/Serialization/">
      <xsl:attribute name="xsi:type">
         <xsl:value-of select="'ser:guid'" />
	 <xsl:value-of select="$param1" />
      </xsl:attribute>
    </Id>   
   <LogicalName xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
       custom_stateorprovince</LogicalName>
   <Name xmlns="http://schemas.microsoft.com/xrm/2011/Contracts" />  
</value>
</xsl:template>

So what did we just do?  We once again have a value node with a lot of stuff jammed in there.  Our “type” is EntityReference and has three elements underneath it: Id, LogicalName, Name.  It seems that only the first two are required.  The Id (which is of type guid) accepts the record identifier for the referenced entity, and the LogicalName is the friendly name of the entity.  Note that in real life, you would probably want to use an orchestration to first query Dynamics CRM to get the record identifier for the referenced entity, and THEN call the “create” service.  Here, I’ve assumed that I know the record identifier ahead of time.

This second page of my map now looks like this:

2011.5.20crm06

We’re now ready to deploy.  After deploying the solution, I imported the generated binding file that in turn, created my send port.  Because I am doing a messaging only solution and I don’t want to build a pipeline component which sets the SOAP operation to apply, I stripped out all the “actions” in the SOAP action section of the WCF-Custom adapter. 

 2011.5.20crm07

After creating a receive location that is bound to this send port (and another send port which listens to responses from the WCF-Custom send port and sends the CRM acknowledgements to the file system), I created an valid XML instance file.  Notice that I have both the option set ID and referenced entity ID in this message.

2011.5.20crm08

After sending this message in, I’m able to see the new record in Dynamics CRM 2011. 

2011.5.20crm09

Neato!  Notice that the Address Type and State or Province values have data in them.

Overall, I wish this were a bit simpler.  Even if you use the CRM SDK and build a proxy web service, you still have to pass in the entity reference GUID values and option set numerical values.  So, consider strategies for either caching slow-changing values, or doing lookups against the CRM services to get the underlying GUIDs/numbers.

Special thanks to blog reader David Sporer for some info that helped me complete this post.

About these ads


Categories: BizTalk, Dynamics CRM

13 replies

  1. address2stateorprovinceid

    <——— es incorrecto

    custom_stateorprovince

    ———————————————————————————————————

    address2stateorprovinceid

    <——— es correcto

    custom_stateorprovince

    • address2stateorprovinceid

      Id xmlns=”http://schemas.microsoft.com/xrm/2011/Contracts”
      xmlns:ser=”http://schemas.microsoft.com/2003/10/Serialization/”
      xsl:attribute name=”xsi:type”
      xsl:value-of select=”‘ser:guid'” /
      xsl:value-of select=”$param1″ /
      /xsl:attribute <——— es incorrecto
      /Id

      custom_stateorprovince

      ———————————————————————————————————

      address2stateorprovinceid

      Id xmlns=”http://schemas.microsoft.com/xrm/2011/Contracts”
      xmlns:ser=”http://schemas.microsoft.com/2003/10/Serialization/”
      xsl:attribute name=”xsi:type”
      xsl:value-of select=”‘ser:guid'” /
      /xsl:attribute <——— es correcto
      xsl:value-of select="$param1" /
      /Id

      custom_stateorprovince

  2. I used the example adapted to my map and it worked correctly, but for a really particular map i’m using namespaces, so the key tag must to be in the form:

    when i added the ns1:, have a problem building the project, the system throws the next error:

    Exception Caught: ‘ns1′ is an undeclared prefix. Line 124, position 4.

    how can i fix this error?

  3. Hi,
    The lookcode in this Post doesnot work. I have added a new one on my blog. Hope it helps you.

    http://biztalkconnect.blogspot.com/2012/04/crm-2011-attribute-lookup-integrating.html

    • There could be a typo error for the look up example here. the param1 node should be outside of “attribute name=xsi:type” node, to be exact immediately after. so you will have attribute attribute -> ser:guid ->/attribute -> param1. that is what Ing Omar Salas tried to say in the first comment there.

  4. can we perform composite operations on crm entities when using typed proxy? kinna like we do it with SQL adapter… If ues, then

  5. Please refer to following link in which I am trying to retrive contact information by using a Retrive schema. But I am not able to do that.

    http://social.msdn.microsoft.com/Forums/sqlserver/en-US/be9492c1-fd51-493e-a833-5dc97a292eab/mapping-to-crm-2011-entity-retrive-node-columnset-fields

  6. What an invaluable resource. Thanks! My question is what other native types can i pass, apart from string. And what is where do i find the XML syntax expected – I need to pass DB types int, datetime and money

Trackbacks

  1. Distributed Weekly 104 — Scott Banwart's Blog
  2. Adding Dynamics CRM 2011 Records from a Windows Workflow Service « Richard Seroter's Architecture Musings
  3. Microsoft Dynamics CRM Customers in Search of Integration, Part 2: Importance of Support - MSDynamicsWorld.com CRM Community Full Articles - CRM Non-Technical Blogs - Microsoft Dynamics Community
  4. BizTalk and CRM first AID – Ask to CRM « Nino Crudele's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 268 other followers

%d bloggers like this: