Do you understand MergeOptions?

If you use LINQ queries with the OrganizationServiceContext then understanding MergeOptions is vital. At the end of this post I describe the most common 'gotcha' that comes from not fully understanding this setting. The OrganizationServiceContext implements a version of the 'Unit of Work' pattern (http://martinfowler.com/eaaCatalog/unitOfWork.html ) that allows us to make multiple changes on the client and then submit with a single call to 'SaveChanges'. The MergeOption property alters the way that the OrganizationServiceContext handles the automatic tracking of objects when returned from queries. It is important to understand what's going on since by default LINQ queries may not return you the most recent version of the records from the server, but rather a 'stale' versions that is currently being tracked. What is this 'Merge' they speak of?! The SDK entry on MergeOptions talks about 'Client side changes being lost' during merges. The term 'merge' is nothing to do with merging of contacts/leads/accounts – but describes what happens when the server is re-queried within an existing context and results from a previous query are returned rather than new copies of each record. It is a record ID based combination, not an attribute merge – so a record is either re-used from the current context, or a new instance is returned that represents the version on the server. In order to describe the different options, consider the following code: // Query 1 var contacts = (from c in context.ContactSet select new Contact { ContactId = c.ContactId, FirstName = c.FirstName, LastName = c.LastName, Address1City = c.Address1City

            }).Take(1).ToArray();

// Update 1 Contact contact1 = contacts[0]; contact1.Address1_City = DateTime.Now.ToLongTimeString(); context.UpdateObject(contact1);

// Query 2 var contacts2 = (from c in context.ContactSet select c ).Take(2).ToArray();

// Update 2 var contact2 = contacts2[0]; contact2.Address1_City = DateTime.Now.ToLongTimeString(); context.UpdateObject(contact2);

// Save Changes context.SaveChanges();

MergeOption.NoTracking Perhaps the best place to start is the behaviour with no tracking at all.

Query 1 – Will return all matching contacts but not add them to the tracking list Update 2 – Will throw and exception because the contact is not being tracked. You would need to use context.Attach(contact) to allow this update to happen Query 2 – This query will pull down new copies of all contacts from the server include a new version of contact 1 Update 2 – We now have two version of the same contact with different city attribute value. The UpdateObject will fail without Attach first being called. If you attempt to attach contact2 after attaching contact1 you will receive the error 'The context is already tracking a different 'contact' entity with the same identity' because contact1 is already tracked and has the same ID.

MergeOption.AppendOnly (Default Setting) When using the OrganizationServiceContext, by default it will track all objects that are returned from LINQ queries. This means that the second query will return the instance of the contacts that have already been returned from query 1. Critically this means that any changes made on the server between query 1 and query 2 (or any additional attributes queried using projection) will not be returned.

Query 1 – Will return all matching contacts and add them to the tracking list Update 2 – Will succeed because the contact is being tracked Query 2 – Will return the same instances that are already being tracked. The only records that will be returned from the server will be those that are not already being tracked. This is the meaning of 'AppendOnly'. The query still returns the data from the server, but the OrganizationServiceContext redirects the results to the instances already in the tracking list meaning that any changes made on the server since Query 1 will not be reflected in the results. Update 2 – Will succeed since contact1 and contact2 are the same object. Calling UpdateObject on the same instance more than once is acceptable.

MergeOption.PreserveChanges PreserveChanges is essentially the same as AppendOnly except:

Query 2 – Will return the same instances that are already being tracked provided they have an EntityState not equal to Unchanged. This means that contact2 will be the same instance as contac1 because it has been updated, but other instances in the contacts1 and contacts2 results will be new instances.

The result of this is that queries will not pick up the most recent changes on the server if a tracked version of that record has been edited in the current context. MergeOption.OverwriteChanges With a MergeOption of OverwriteChanges, the query behaviour will effectively be as per NoTracking however the tracking behaviour is like AppendOnly and PreserverChanges:

Query 1 – Will return all matching contacts and add each on to the tracking list (as per AppendOnly and PreserveChanges) Update 2 – Will succeed because the contact is being tracked (as per AppendOnly and PreserveChanges) Query 2 – This query will pull down new copies of all contacts from the server include a new version of contact 1 (as per NoTracking). Previously tracked contact1 will no longer be tracked, but the new version (contact2) will be. Update 2 – Will succeed and the values on contact1 will be lost.

The MergeOption has a subtle but important effect on the OrganizationServiceContext, and without truly understanding each setting you might see unexpected results if you stick with the default 'AppendOnly'. For instance, you might update the value on the server between queries, but because a record is already tracked, re-querying will not bring down the latest values. Remember that all of this behaviour only is true for the same context – so if you are creating a new context then any previously tracked/modified records will no longer be tracked. LINQ Projection 'Gotcha' The most common issue I see from not fully understanding MergeOptions (and yes I made this mistake too! ) is the use of the default AppendOnly setting in conjunction with LINQ projection. In our code example Query 1 returns a projected version of the contact that only contains 4 attributes. When we re-query in Query 2 we might expect to see all attribute values but because we are already tracking the contacts our query will only return the previously queried 4 attributes! This can hide data from your code and cause some very unexpected results! In these circumstances, unless you really need tracking and fully understand MergeOptions, I recommend changing the MergeOptions to 'NoTracking'. @ScottDurow

How to restore a hidden button on the CRM 2013 Command Bar

The new Dynamics CRM 2013’s command bar has deliberatly limited space for buttons due to the ‘intentionally constrained’ user interface design. The idea being that if you limit the space for buttons, then designers will be forced to only show those that are absolutely necessary and the user experience will be improved. As result, many of the buttons from the CRM 2011 Ribbon Bar have been removed from the CRM 2013 Command Bar. The CRM2011 Ribbon Buttons are still there, but hidden using a new RibbonXml Display Rule named 'Mscrm.HideOnCommandBar'. This article shows you how to restore those buttons to the Command Bar that your users absolutely must have using the Ribbon Workbench for CRM2013. 1. Create a solution containing the entities that you wish to restore buttons for. This example uses the ‘Case’ entity, and we are restoring the ‘Connect’ button on the ‘Form’ command bar. Before customising, the Form Command Bar looks like the following: You’ll notice that only 5 buttons are shown until buttons are added to the ‘overflow’ menu. The ‘Connect’ button is not here since it was deemed unessential. 2. Open the solution containing the Case entity in the Ribbon Workbench for CRM 2013 and select the ‘incident’ entity if not already selected. You will see by default the Command Bar is selected.   3. In order to locate the button we want to restore, click on the ‘Ribbon’ selector to show the Ribbon. This will show the Ribbon Design surface. 4. Select the ‘Form’ ribbon using the dropdown on the top right of the design surface, then select the ‘Connect’ button and Right-Click ‘Customize Command’ 5. Locate the Customised Command in the ‘Solution Elements’ tab under ‘Commands’ 6.  In the Edit Display Rules dialog, select the ‘Mscrm.HideOnCommandBar’ rule and click the ‘<Remove’ button. 7.  Important: Locate the following Display Rules, and set the ‘IsCore’ property to ‘True’ – this will prevent them from being customised as well: a.      Mscrm.HideOnCommandBar b.      Mscrm.CreateConnection c.      Mscrm.IsConnectionsEnabledPrimary d.      Mscrm.HideOnModern 8. Important: Locate the ‘Mscrm.FormStateExistingOrReadOnlyOrDisabled’ Enable Rule, and set the ‘IsCore’ property to ‘True’ 9. Click ‘Publish’ 10 Now when you refresh the Case Form, you will see the Connect button again. 11  You’ll notice that only the default button is shown – so if you use the drop down, you’ll only get the ‘Connect to Another’ option. To enable the ‘To Me’ button repeat the process for the ‘To Me’ button: Remember to make sure that only the buttons that are really needed are included - the Command Bar has been constrained intentially to give your users the best experience. @ScottDurow  

Microsoft.Xrm.Client Part 1: CrmOrganizationServiceContext and when should I use it?

The Dynamics CRM SDK documentation is amongst the best I've seen for any business application. It provides numerous code examples and walk through ranging from the basics all the way through to advanced topics. One of the areas that perhaps needs a little more clarification is the 'Developer Extensions' topic. This post is part 1 of a series on this SDK 'blind spot' so you can get the most out of this value part of the SDK. The Microsoft.Xrm.Client namespace comes from the assembly of the same name 'microsoft.xrm.client.dll'. It is not available to plugin or workflow code and is designed specifically for use in Windows .NET clients or ASP.NET clients that communicate with Dynamics CRM. It provides the following key features; each will be a topic of separate blog post.

CrmSvcUtil & OrganizationServiceContext enhancements such as lazy loading Simplified Connection Management with Connection Dialog UI Client Side caching extensions Utility Extension functions for common tasks to speed up client development Organization Service Message utility functions to make it easy to call common messages such as BulkDelete, Add Member to Team etc. Objects to support the Microsoft.Xrm.Portal extensions

One area that I do get asked about quite frequently is the difference between the CrmOrganizationServiceContext and your common-all-garden OrganizationServiceContext. This question is the subject of this post. Both of these classes implement the IOrganziationServiceContext interface and so once created they can be used interchangeably, but before you do this it is important to understand what is going on and why. To use the CrmOrganizationServiceContext correctly, your journey should start with the Developer Extensions to the CrmSvcUtil. Rather than using the standard CrmSvcUtil flavour, you need to modify your command to include the following: CrmSvcUtil.exe /codeCustomization:"Microsoft.Xrm.Client.CodeGeneration.CodeCustomization,Microsoft.Xrm.Client.CodeGeneration" /url:http://<server>/<org>/XRMServices/2011/Organization.svc /out:"Xrm.cs" /namespace:Xrm /serviceContextName:XrmServiceContext This will give you a very familiar looking early bound code file but with some critical differences:

The Entity classes now inhertit from Microsoft.Xrm.Client.CrmEntity and not Microsoft.Xrm.Sdk.Entity The generated Service Context will inhertit from Microsoft.Xrm.Client.CrmOrganizationServiceContext and not Microsoft.Xrm.Sdk.Client.OrganizationServiceContext

The XrmServiceContext has some new constructors that allow you to create the OrganizationService from the simplified connection API (Part 2 of this series), but apart from that there aren't really any differences. The magic is what is going on in the new base classes that allow Lazy Loading of the Relationship attributes. In order to access a relationship property using the standard OrganizationServiceContext you would need to use: ctx.LoadProperty(ParentAccount, (a) => a.contactcustomeraccounts); Note: This is using the LINQ expression to specify the relationship – which is much easier than the 'traditional approach' of specifying the relationship name as string! ..but using the CrmOrganizationServiceContext, you can now simply query the relationship and the values will be automatically 'lazy loaded' for you. It is called 'lazy' because it will only load when it is first called: var relatedContacts = (from c in acc.contactcustomeraccounts select c); This allows you to simply query the object graph as though it was all in memory on the client already without worrying if it has been already loaded. With this automatic expand behaviour comes with some important points to watch for:

Every time you perform a LINQ query against a lazy loaded property, the CrmOrganizationService will first query the relationship metadata to and then it will return all related entities using a Retrieve request with the RelatedEntitiesQuery populated. It makes sense to use this technique only when you need to load all related entities as part of a client side caching strategy (see Part 3). Any 'where' filters will be applied on the client side once all the related entities are retrieved. If you need to perform server side filtering, it would best to use a standard OrganizationServiceContext.CreateQuery<T> Joins will be applied re-cursively by repeatedly querying each relationship – so again if you need complex joins and don't want all the entities on the client use CreateQuery<T> and a server side query. Any LINQ projections you use in the query will not be used since all attributes are returned for the related entities. The idea again is that a caching strategy is used so that any filters can be applied on the client side without re-requesting the data from the server.

The LINQ query above will result in the following requests being made: First the relationship query: <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <request i:type="a:RetrieveRelationshipRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts"> <a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic"> <a:KeyValuePairOfstringanyType> <b:key>MetadataId</b:key> <b:value i:type="c:guid" xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/">00000000-0000-0000-0000-000000000000</b:value> </a:KeyValuePairOfstringanyType> <a:KeyValuePairOfstringanyType> <b:key>RetrieveAsIfPublished</b:key> <b:value i:type="c:boolean" xmlns:c="http://www.w3.org/2001/XMLSchema">false</b:value> </a:KeyValuePairOfstringanyType> <a:KeyValuePairOfstringanyType> <b:key>Name</b:key> <b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">contactcustomeraccounts</b:value> </a:KeyValuePairOfstringanyType> </a:Parameters> <a:RequestId i:nil="true" /> <a:RequestName>RetrieveRelationship</a:RequestName> </request> </Execute> </s:Body> </s:Envelope>

And then the actual query: <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <request i:type="a:RetrieveRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts"> <a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic"> <a:KeyValuePairOfstringanyType> <b:key>Target</b:key> <b:value i:type="a:EntityReference"> <a:Id>9345b249-17ee-e211-9d20-000c299ffe7d</a:Id> <a:LogicalName>account</a:LogicalName> <a:Name i:nil="true" /> </b:value> </a:KeyValuePairOfstringanyType> <a:KeyValuePairOfstringanyType> <b:key>ColumnSet</b:key> <b:value i:type="a:ColumnSet"> <a:AllColumns>false</a:AllColumns> <a:Columns xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays" /> </b:value> </a:KeyValuePairOfstringanyType> <a:KeyValuePairOfstringanyType> <b:key>RelatedEntitiesQuery</b:key> <b:value i:type="a:RelationshipQueryCollection"> <a:KeyValuePairOfRelationshipQueryBaseXPsK4FkN> <b:key> <a:PrimaryEntityRole i:nil="true" /> <a:SchemaName>contactcustomeraccounts</a:SchemaName> </b:key> <b:value i:type="a:QueryExpression"> <a:ColumnSet> <a:AllColumns>true</a:AllColumns> <a:Columns xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays" /> </a:ColumnSet> <a:Criteria> <a:Conditions /> <a:FilterOperator>And</a:FilterOperator> <a:Filters /> </a:Criteria> <a:Distinct>false</a:Distinct> <a:EntityName>contact</a:EntityName> <a:LinkEntities /> <a:Orders /> <a:PageInfo> <a:Count>0</a:Count> <a:PageNumber>0</a:PageNumber> <a:PagingCookie i:nil="true" /> <a:ReturnTotalRecordCount>false</a:ReturnTotalRecordCount> </a:PageInfo> <a:NoLock>false</a:NoLock> </b:value> </a:KeyValuePairOfRelationshipQueryBaseXPsK4FkN> </b:value> </a:KeyValuePairOfstringanyType> </a:Parameters> <a:RequestId i:nil="true" /> <a:RequestName>Retrieve</a:RequestName> </request> </Execute> </s:Body> </s:Envelope>

This functionality is specific built for building Client applications that connect to Dynamics CRM, to make displaying CRM data to the user easier. It is not intended for use in Plugins or Workflow Activities. Next up is Part 2 on the simplified connection management extensions. @ScottDurow

User Impersonation in Plugins, Workflow and Dialogs

I've recently had a few questions around the UserId and InitiatingUserId properties of the execution context, so I thought I'd attempt to clear up any confusion. The simple fact around user impersonation in Dynamics CRM is that it isn't simple! I could write pages on the subject but instead here are 2 grids that explain everything you need to know. The key point to remember is that these User Identities have very little to do with the Windows Authentication Identity (service accounts etc.) – they are all GUID's that refer to User records within your Dynamics CRM Organisation. Impersonation in Plugins The following grid shows the various user identities present for Plugins. 'Triggering User' refers to the logged in user who saves the record in Dynamics CRM and triggers a Plugin to fire. It's also worth noting that offline plugins will fire once offline as shown and then again on the server.

Impersonation in Dialogs and Workflows The following grid shows the various user identities present for Workflows and Dialogs. The interesting thing here is the difference between Parent and Child Automatic Workflows.

Hope that settles the matter - I'm sure it won't! @ScottDurow

jQuery and jQuery UI with Dynamics CRM 2011 & 2013

Since I’ve been converting Silverlight web resources over to Html & JavaScript and working on www.SparkleXrm.com , I’ve worked extensively with jQuery and jQuery-UI. In the early days of Dynamics CRM 2011, you could use both these libraries without a problem, but with the Activity Feeds solution an instance of jQuery appeared that interfered with your custom scripts. This is still the case in Dynamics CRM 2013 and so here are some simple steps to ensure your libraries are safe and will co-exist with other instances from other solutions. 1. Decide on a custom ‘namespace’ for your jQuery library. I am using ‘xrmjQuery’ 2. On the end of your jquery.js script add the following line: /* jQuery script goes here */ window.xrmjQuery = jQuery.noConflict(true);

  1. Inside your jquery_ui.js script (notice the ‘-‘ has been changed to an underscore since CRM doesn’t allow them in web resource names), wrap the whole file in the following lines: (function ($,jQuery) { /*! jQuery UI Goes here */ })(window.xrmjQuery,window.xrmjQuery);

  2. Inside your JavaScript web resource that use jQuery and jQuery-UI, wrap your code in the following: (function($){ // Your Javascript goes here and can reference $ as usual // e.g. var someField = $('#fieldName'); })(window.xrmjQuery);

This technique is called encapsulation and namespacing of jQuery. My friend Carsten also has a blog post on a similar theme. www.SparkleXrm.com uses the same technique and namespace is also ‘xrmjQuery’, so if you would like to quickly get access to the jQuery libraries in Dynamics CRM, you can install the SparkelXrm managed solution and include the web resource named ‘sparkle/js/SparkleXrmUIDependancies.js’ – this is a single library that has both jQuery, jQueryUI as well as a few other goodies such as Knockout JS!   @ScottDurow

Ribbon ‘XML’ Workbench for Dynamics CRM 2013 with a silent ‘XML’!

After much deliberation and consultation, I have decided to stick with the name 'Ribbon Workbench' rather than rename to CommandBar Workbench. Here are some of the reasons behind this decision:

The Command Bar in CRM 2013 is still defined with RibbonXml, but rendered differently. A DisplayRule is used to exclude buttons from the CommandBar. The Ribbon is still present on non-refresh entities and in Outlook so it's important to still have support for Ribbon editing. Since the Ribbon Xml remains unchanged, it's important to understand and differentiate between Tabs/Groups and Layouts. The Ribbon Workbench is already an established 'brand' than people know about. So until we have CommandBar XML in a future version of Dynamics CRM – it'll always be the Ribbon 'XML' Workbench with a silent 'XML'!

The new version has the following improvements:

Dynamic switching between the Command Bar and Ribbon view UI refreshed to match Dynamics CRM 2013 Performance Optimisations Support for new Dynamics CRM 2013 schema

For those of you with access to the Dynamics CRM 2013 beta - the Ribbon Workbench for Dynamics CRM 2013 beta is available for download here:http://www.develop1.net/public/page/Ribbon-Workbench-for-Dynamics-CRM-2011.aspx @ScottDurow