Archive for the ‘CRM’ Category

Query MS CRM XML Entity with XQuery and LINQ

In our company we have been working on a large MSCRM 2011 project. Last week, I was asked to create a report listing all the visible fields for each entity in the solution. During my search, I found a few different ways to do it, but the most fun way was querying the XML.
The XML is created when the solution is exported. It’s normally several levels deep and even when the structure would depend on the solution the XML listed below is an example of how it would looks like.

<Entities>
    <Entity>
      <Name LocalizedName="Account" OriginalName="Account">Account</Name>
      <ObjectTypeCode>1</ObjectTypeCode>
      <EntityInfo>
        <entity Name="Account">
          <LocalizedNames>
            <LocalizedName description="Account" languagecode="1033" />
          </LocalizedNames>
          <LocalizedCollectionNames>
            <LocalizedCollectionName description="Accounts" languagecode="1033" />
          </LocalizedCollectionNames>
          <Descriptions>
            <Description description="Business." languagecode="1033" />
          </Descriptions>
   <attributes>
		<attribute PhysicalName="Category">
			…
	<attribute>
   </attributes>
</entity>
      </EntityInfo>
   <FormXml>
        <forms type="main">
          <systemform>
            <formid>{b053a39a}</formid>
            <form>
              <hiddencontrols>
                <data id="addressid" datafieldname="addressid" classid="{}" />
                <data id="address2” datafieldname="address2" classid="{}" />
              </hiddencontrols>
		  <tabs>
                <tab name="general" verticallayout="true" id=”" IsUserDefined="0">
                  <labels>
                    <label description="General" languagecode="1033" />
                  </labels>
                  <columns>
                    <column width="100%">
<sections>
  <section name="account information" showlabel="false" showbar="false" id="{}" IsUserDefined="0">
                          <labels>
                            <label description="Information" languagecode="1033" />
                          </labels>
                          <rows>
                            <row>
                              <cell id="{}">
                                <labels>
                                  <label description="Name" languagecode="1033" />
                                </labels>
                                <control id="name" classid="{}" datafieldname="name" />
                              </cell>
                              <cell id="{}">
                                <labels>
                                  <label description="Phone" languagecode="1033" />
                                </labels>
                                <control id="telephone1" classid="{}" datafieldname="telephone1" />
                              </cell>
                            </row>
                            <row>
                              <cell id="{}" showlabel="false" >
                                <labels>
                                  <label description="Contact" languagecode="1033" />
                                </labels>
                                <control id="primarycontactid" classid="{}" datafieldname="primarycontactid">
                                  <parameters>
                                    <FilterRelationshipName>customer_accounts</FilterRelationshipName>
                                    <DependentAttributeName>parentcustomerid</DependentAttributeName>
                                    <DependentAttributeType>account</DependentAttributeType>
                                    <AllowFilterOff>true</AllowFilterOff>
                                  </parameters>
                                </control>
                              </cell>
                              <cell id="{}" showlabel="true" >
                                <labels>
                                  <label description="Other Phone" languagecode="1033" />
                                </labels>
                                <control id="telepho" classid="{}" datafieldname="telep" />
                              </cell>
                            </row>
                            <row>
                              <cell id="{}">
                                <labels>
                                  <label description="Parent" languagecode="1033" />
                                </labels>
                                <events>
                                  <event name="setparams" application="true" active="true">
                                    <InternalHandlers>
                                      <Handler handlerUniqueId=" " enabled="true" />
                                    </InternalHandlers>
                                  </event>
                                </events>
                                <control id="parentaccountid" classid="{}" datafieldname="parentaccountid" />
                              </cell>
                              <cell id="{ }">
                                <labels>
                                  <label description="Fax" languagecode="1033" />
                                </labels>
                                <control id="fax" classid="{}" datafieldname="fax" />
                              </cell>
                            </row>
                            <row>
                              <cell id="{ }">
                                <labels>
                                  <label description="E-mail" languagecode="1033" />
                                </labels>
                                <control id="emailadd" classid="{}" datafieldname="emailadd" />
                              </cell>
                              <cell id="{ }">
                                <labels>
                                  <label description="Web Site" languagecode="1033" />
                                </labels>
                                <control id="websiteurl" classid="{}" datafieldname="websiteurl" />
                              </cell>
                            </row>
                          </rows>
                        </section>
             </sections>
                    </column>
                  </columns>
                </tab>
</tabs>
</form>
     </systemform>
        </forms>
      </FormXml>
    </Entity>
</Entities>

'

Take into consideration that we have several entities and those entities have multiple tabs, sections, controls and labels. The listing above is just an example of what MS CRM exports in XML format. It shouldn’t be consider as a real entity. Having said that, lets continue with the real fun.

My task was to find all the visible and enabled fields in the solution. I also needed to know, if the fields belong to the Account entity or any other entity and I just needed to retrieve the fields from the Main form not the Mobile form.

Before we go further, is important to say that I had to retrieve the Label description, but I had to check the cell element, “Showlabel” attribute which controls the visibility as you can see on the next example.

<cell id="{}" showlabel="true" >
  <labels>
    <label description="Other Phone" languagecode="1033" />
  </labels>
  <control id="telepho" classid="{}" datafieldname="telep" />
 </cell>

'

Like I said before, there are different ways to do this. Here are a couple examples.
The first I used was XQuery and FLWOR expressions.

Basically it searches through the XML verifies if the “showlabel” attribute is either not there or set to true and retrieves the names.


SELECT ent.vals.value('@OriginalName', 'varchar(max)') AS Entity, ent.vals.value('@datafieldname', 'varchar(max)') FieldName
FROM @xml.nodes('for $en in //Entity
return ($en/Name,(for $q in ($en/FormXml/forms/systemform/form/tabs/tab/columns/column/sections/section/rows/row/cell)
where (empty($q/@showlabel) or ($q/@showlabel=&amp;quot;true&amp;quot;))
return $q/control)) ') ent(vals)

'

It returns the Entity name in one column follow by the Fields. It looks like this:

Another way to query is using Linq to XML. The statement looks like this:


var xrmEntities =   from e in doc.Elements(&amp;quot;Entity&amp;quot;)
                        from c in e.Elements(&amp;quot;FormXml&amp;quot;).Elements(&amp;quot;forms&amp;quot;).Elements(&amp;quot;systemform&amp;quot;).Elements(&amp;quot;form&amp;quot;)
                                    .Elements(&amp;quot;tabs&amp;quot;).Elements(&amp;quot;tab&amp;quot;)
                                    .Elements(&amp;quot;columns&amp;quot;).Elements(&amp;quot;column&amp;quot;)
                                    .Elements(&amp;quot;sections&amp;quot;).Elements(&amp;quot;section&amp;quot;)
                                   .Elements(&amp;quot;rows&amp;quot;).Elements(&amp;quot;row&amp;quot;)
                                    .Elements(&amp;quot;cell&amp;quot;)
                        where (string)c.Attribute(&amp;quot;showlabel&amp;quot;) == &amp;quot;true&amp;quot; || c.Attribute(&amp;quot;showlabel&amp;quot;) == null
                        from l in c.Elements(&amp;quot;labels&amp;quot;)
                        let formName = e.Element(&amp;quot;Name&amp;quot;).Attribute(&amp;quot;LocalizedName&amp;quot;).Value
                        let fieldName = l.Element(&amp;quot;label&amp;quot;).Attribute(&amp;quot;description&amp;quot;).Value
                        orderby formName, fieldName
                        select new {Entity = formName, Field = fieldName };
    xrmEntities.Count().Dump();
    xrmEntities.Dump();

//”doc”  variable loads the XML file.

The result returned by Linq is probably easier to understand. It looks like this.

Either way returns the Fields Names so, It’s up to you to decide what to use Linq or XQuery. Both of them are good things to learn as a developer.

Tags: , , , , , , , ,


Microsoft CRM 2011: Immediately Open a Record That Was Updated Using oData

This is a quick modification to the Microsoft CRM 2011: Update oData Examples article we posted a while ago. In the event that you would prefer to just pop up a record that you’ve updated or created using oData instead of making your user find it on their own, you can use the AJAX “success” attribute to execute whatever code you want when the update/create is complete.

For instance, in the following “updateContact” function from the previous article, I’ve added code to build a URL, then open a window:

function updateContact(id, contactObject) {

  //Parse the entity object into JSON
  var jsonEntity = window.JSON.stringify(contactObject);

  //Asynchronous AJAX function to Update a CRM record using OData
 $.ajax({
    type: &quot;POST&quot;,
    contentType: &quot;application/json; charset=utf-8&quot;,
    datatype: &quot;json&quot;,
    data: jsonEntity,
    url: Xrm.Page.context.getServerUrl() + &quot;/XRMServices/2011/OrganizationData.svc/ContactSet(guid'&quot; + id + &quot;')&quot;,
    beforeSend: function (XMLHttpRequest) {
      //Specifying this header ensures that the results will be returned as JSON.
      XMLHttpRequest.setRequestHeader(&quot;Accept&quot;, &quot;application/json&quot;);

      //Specify the HTTP method MERGE to update just the changes you are submitting.
      XMLHttpRequest.setRequestHeader(&quot;X-HTTP-Method&quot;, &quot;MERGE&quot;);
    },
    success: function (data, textStatus, XmlHttpRequest) {
      if(Xrm.Page.getAttribute('new_opencontactonsave').getValue() == true) {
        var linkUrl = Xrm.Page.context.getServerUrl() + &quot;/main.aspx?etc=2&amp;extraqs=formid%3d894cc46a-b0cb-4ab0-8bf6-200544e46a2d&amp;id=%7b&quot; + id + &quot;%7d&amp;pagetype=entityrecord&quot;;

        var windowWidth = screen.width * .5;
        var windowLeft = windowWidth * .5;

        var windowHeight = screen.height * .75;
        var windowTop = (screen.height - windowHeight) * .5;

        var options = &quot;left=&quot; + windowLeft + &quot;,width=&quot; + windowWidth + &quot;,top=&quot; + windowTop + &quot;,height=&quot; + windowHeight;

        window.open(linkUrl,&quot;_blank&quot;,options);
      }
    }
  });
}

In this case, we’re using the GUID for the Contact we just updated when building the URL, but, if we inserted a Contact record, we could use the result data to find the GUID of the record with something like “data.d.ContactId”. The quickest way to get the values for the other querystring variables, “etc” and “extraqs”, is to open a record of whatever entity you’re interested in, click “Copy a Link”, then pull the values from there. All that’s left is to set the window options that you want and open it up!

Contact Header

The updated CRM 2011 solution file can be downloaded here!

Tags: , , , , ,


Microsoft CRM 2011 oData Examples

Microsoft CRM has added support for oData in the 2011 release. oData, according to the oData web site “…is a Web protocol for querying and updating data that provides a way to unlock your data and free it from silos that exist in applications today.” What it means is that using an XMLHttpRequest object, you can send a query string to a web service with syntax that is very SQL like and get data back from the web service. It goes beyond that in that it also allows you to update and insert as well. MS CRM did not implement the full oData specification, but it still offers a quite a bit of functionality.

My goal here is to give you two different oData calls to populate some data on a CRM form. I will assume that you have a basic knowledge of CRM, adding JavaScript to forms in 2011 and creating an XMLHttpRequest. Also, I am using jQuery in the form to parse the json that gets returned.

Here’s the scenario that I’m going to implement. On the account main page/detail screen, you need to put data from the contact. I know, I know, contacts appear in a grid, but the customer really wants to see the info for the support contact (a custom attribute I created on the contact) and the most recently created contact at the top of the account screen like this:

Account Screen

Be sure to read the comments in the Javascript – I have a lot of explanations about the oData query in the comments. If you don’t read those, you’ll miss important stuff. Also, remember, this is just a quick intro. Be sure to read the oData URI Conventions to learn more about some of the various query options, too!

I’ve made the solution available for download, but if you want to create the customizations manually, the steps are below.

  1. Create a solution
  2. On the account entity, create the following custom attributes:
    1. new_MostRecentEmail
    2. new_MostRecentFullName
    3. new_MostRecentPhone
    4. new_MostRecentTitle
    5. new_SupportEmail
    6. new_SupportFullName
    7. new_SupportPhone
    8. new_SupportTitle
  3. On the contact entity create the following custom attribute:
    1. new_IsSupportContact
  4. Add two script web resources
    1. Create one and add jQuery (you can download jQuery here) for the code
    2. Create a second resource and add the javascript code further down
  5. Modify the account form to look like the picture above using the fields created above. Make the added fields read-only.
  6. On the account form, add both script resources.
  7. On the form properties, for the form OnLoad event, specify the “onLoad” function in the second script resource you created.
  8. Create a test account and a test contact. Designate one or more contacts as “Is Support Contact”.
  9. Publish your customizations and try it out.
var xp = Xrm.Page;

function onLoad(context) {
    var accountId = xp.data.entity.getId();

    /*  This is the heart of using oData. This is where the query is defined.
        It has very SQL-like syntax although instead of a "where" clause it
        uses "filter". Also, the comparison operators or different. 'eq' instead
        of '=', 'gt' instead of '>", etc. 

        I'm using the oData select keyword to select the four columns I'm interested in.
        Next, I'm using the "top" construct to return a single record.
        After the top is the "orderby" which sorts on "CreatedOn" descending
        so the most recent created record is first. Between the top 1 filter and
        the sort of ModifiedOn descending, the record we want is returned.

        Also note that the ParentCustomerId is a complex type, so you have to
        specify 'ParentCustomerId/Id' to navigate from the ParentCustomerId
        to it's child property 'Id' to get to the actual value.*/
        var mostRecentQuery = "/XRMServices/2011/organizationData.svc/ContactSet?$select=FullName,JobTitle,EMailAddress1,Telephone1&$top=1&$orderby=CreatedOn desc&$filter=ParentCustomerId/Id eq guid'" + accountId + "'";
    getContact(mostRecentQuery, "MostRecent");

    var supportContactQuery = "/XRMServices/2011/organizationData.svc/ContactSet?$select=FullName,JobTitle,EMailAddress1,Telephone1&$filter=new_IsSupportContact eq true";
    getContact(supportContactQuery, "SupportContact");
}

function getContact(oDataQuery, queryName) {
    try {
            var serverUrl;
             /* This is the heart and soul of the whole thing - the actual oData call. */
            serverUrl = Xrm.Page.context.getServerUrl() + oDataQuery;
            var request = new XMLHttpRequest();
            request.open("GET", serverUrl, true);
            request.setRequestHeader("Accept", "application/json");
            request.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            /* Next, we specify the function that we want called when the XMLHttpRequest state
               changes. This will get called on each state change. */
            request.onreadystatechange = function () {
                requestComplete(request, queryName);
            }
            request.send();
    } catch (e) {
        // You probably want to do something other than an alert here.
        alert(e.Description);
    }
}

function requestComplete(request, queryName) {
    /*  A request.readyState of 4 means the request is complete. If
        it's complete and the status is 200 (OK), then we can assign the results
        of the call to our controls on the form.*/
    if (request.readyState == 4 && request.status == 200) {
        // debugger;
        var json = $.parseJSON(request.responseText);
        if ( (json != undefined) && (json.d != undefined) && (json.d.results != undefined) && (json.d.results[0] != null) ) {
            json = json.d.results[0];
            // Note that the way things are set up, it's possible to have more
            // than one "Support Contact" returned but I'm hard coding the results
            // to return the first contact only.
            if (queryName == "MostRecent") {
                xp.getAttribute("new_mostrecentfullname").setValue(json.FullName);
                xp.getAttribute("new_mostrecentphone").setValue(json.Telephone1);
                xp.getAttribute("new_mostrecentemail").setValue(json.EMailAddress1);
                xp.getAttribute("new_mostrecenttitle").setValue(json.JobTitle);
                // As an aside (the field below doesn't exist), when placing values
                // into a numeric field, you will need to use the javascript
                // function parseFloat to prevent CRM type errors.
                //xp.getAttribute("new_numericrank").setValue(parseFloat(json.new_NumericRank));
            } else if (queryName == "SupportContact") {
                xp.getAttribute("new_supportfullname").setValue(json.FullName);
                xp.getAttribute("new_supportphone").setValue(json.Telephone1);
                xp.getAttribute("new_supportemail").setValue(json.EMailAddress1);
                xp.getAttribute("new_supporttitle").setValue(json.JobTitle);
            }
        }
    }
}

P.S. – I noticed right before I posted that the “Is Support Contact Query” doesn’t filter by account, so the same contact will appear regardless of what account you’re looking at. Consider it an exercise for the reader to add that filter. :)

Tags: , , ,


Random Error Message: “The logon attempt failed” in MS CRM 2011 crmsvcutil.exe

I was working with MS CRM 2011 and was attempting to generate strongly typed classes using crmsvcutil.exe for an application that integrates data into MS CRM. Unfortunately, I kept receiving the error “The logon attempt failed” and I was pretty sure it was due to using ADFS and claims based authentication. I was able to verify that by restoring the database to a non-ADFS, non claims-based CRM server, importing the org and successfully generating my classes. It was a pain but it worked. I have had the problem for a while but couldn’t find anything about it – I guess that’s one of the pitfalls of being an early adopter.

I finally searched for the issue again and found I’m not the only one and that the good people at ADX Studio have a solution. I tried it and it worked like a champ! Hopefully it will be fixed in the SDK sooner rather than later, but at least I don’t have to resort to trickeration to get it to work!

Tags: , , ,


Script Compatibility Between MS CRM 4.0 and 2011

During an upgrade from CRM 4.0 to CRM 2011 we discovered an issue in scripting that caused things to break even though scripts are backwards compatible. There is a field/attribute called fullname that is hidden and auto-populated based on first, middle and last names and is saved with the record. The issue was the syntax used in MS CRM 4.0 – while it worked, it wasn’t the “supported” MS CRM method. There are two fixes.

The code that didn’t work was this:

// fullname is a var that is a concatenation of first, last and middle
document.crmForm.new_fullname.value = fullname;

The first way to fix it is to use the CRM 2011 scripting model:

Xrm.Page.getAttribute("new_fullname").setAttribute(fullname);

The second method was to fix it using the proper CRM 4.0 syntax with the “.value” at the end replaced with “.DataValue”:

document.crmForm.new_fullname.DataValue = fullname;

Which is the better way to fix it? If it were me and it’s a small script, I would update the whole script to the CRM 2011 scripting model. If it’s a large script where only a few lines need to be changed, I might be tempted to fix it using the 4.0 method until the whole script can be updated so it’s consistent. Of course, if you have time to update the whole thing and thoroughly test it, then I would do that.

Hopefully this will help someone else during their upgrade process, whether for themselves or on behalf of a customer.

Tags: , , , ,


Random Error Message: Type or namespace name ‘CrmEntityReference’ does not exist in the namespace…

I created a project (call it “Project A”) a while ago using the Advanced Developer Extensions and used crmsvcutil.exe to generate the classes to be used in my .NET project. I recently had a need to create another .NET project (call it “Project B”) using the Advanced Developer Extensions. Instead of using the DLL in the SDK\microsoft.xrm folder that I had recently re-downloaded/updated, I just copied the Microsoft.Xrm.Client DLL from “Project A”. When I went to build the project it failed with the error message:

Error 1 The type or namespace name 'CrmEntityReference' does not exist
in the namespace 'Microsoft.Xrm.Client' (are you
missing an assembly reference?)

After doing some digging around, I discovered that the latest version of crmsvcutil.exe in the SDK generates the code a bit differently. Fields such as an ownerid used to be generated like this:

[global::Microsoft.Xrm.Client.Linq.CrmProperty("ownerid")]
public global::Microsoft.Crm.Sdk.Owner ownerid
	{
		get { return this.GetPropertyValue<global::Microsoft.Crm.Sdk.Owner>("ownerid"); }
		set { this.SetPropertyValue("ownerid", value, typeof(global::Microsoft.Crm.Sdk.Owner)); }
	}

but instead has been changed to this:


[global::Microsoft.Xrm.Client.Linq.CrmProperty("ownerid", "owneridLabel")]
public global::Microsoft.Xrm.Client.CrmEntityReference ownerid
	{
		get { return this.GetPropertyValue<global::Microsoft.Xrm.Client.CrmEntityReference>("ownerid"); }
		set { this.SetPropertyValue("ownerid", value, typeof(global::Microsoft.Crm.Sdk.Owner)); }
	}

The difference is in the actual type – instead of being a type of “Microsoft.Crm.Sdk.Owner” it is ”Microsoft.Xrm.Client.CrmEntityReference”. Since that class exists in the microsoft.xrm.client assembly, I knew something had to be different. At first I thought I had pointed to a CRM 2011 dll instead of 4.0 version because the CrmEntityReference is something that you see in CRM 2011. I double checked and I was correct, it was a 4.0 version assembly. The fix at that point was simply a matter of removing my reference to the older Microsoft.Xrm.Client.dll assembly and adding in the one with the latest version from my recently updated SDK. Everything built just fine after that.

The moral of the story? If you update your SDK, make sure that any assemblies you rely on haven’t changed their types or your code may break!

Tags: , , , , , ,


Customizing and Developing for MS CRM 2011

MS CRM 2011 has been officially released. I finally had some time to spend looking at it last week and I really, really like what I see from a customization and development perspective. Some of the pain has been taken out of customizing MS CRM. But, as with any new version of software, good documentation is hard to find. Since I spent a good part of my learning & playing with MS CRM 2011 finding documentation, I thought I would share some of the links I’ve found that serve as good references and resources to help me get up to speed on the new version.

Form Scripting

When it comes to form scripting, the whole model has changed. Things used to be referenced by “crmForm.property”, but that has been deprecated. It still works, but you should begin using the newly provided Xrm.Page object model. This article explains what the Xrm.Page model is, the collections of various items in the page model as well as a good overview.

Web Services

The web services in MS CRM have changed as well. It used to be there were two services: the main data service and the metadata web service. MS CRM 2011 still has two web services, but they are different. The first is a RESTful web service that uses oData. If you’re not familiar with oData, you can check it out here. [Update 2011-06-27: I've added a post on our blog with some examples of oData in CRM 2011.] Blogger TechHike has a post on “How to get started with oData” that explains the fundamentals of oData. If you want to use oData in CRM 2011, you can find out how to use it in CRM here. Be forewarned that the MS CRM oData service doesn’t fully implement all oData functions. The other web service uses SOAP. You can read about the differences and which is preferred for various scenarios here.

JavaScript

CRM 2011 allows you to include JavaScript libraries – usable blocks of code that can be shared amongst multiple forms and events. Before you had to resort to lots of trickeration to get things like this done. Here is an overview.

Plugins

Plugins aren’t new, but there are some new things about plugins. For a great overview of plugins, this page is a great springboard for other links.

Lastly, for some great videos that explain lots of things about MS CRM, Channel 9 at MSDN has a library of videos that covers a wide variety of topics. In my experience you can just jump right in on a given video that interests you and you won’t be lost if you haven’t seen the others.

CRM 2011 brings a lot of new things to the table from a customization and development perspective and learning them all will take time. Hopefully these links will get you started or at least give you a reference point. I suspect I’ll be bringing up this post for my own use in the future!

Tags: , , ,


Random Error Message: Mandatory updates for Microsoft Dynamics CRM could not be applied successfully

I was installing the Microsoft Outlook CRM client and got the error message:

Mandatory updates for Microsoft Dynamics CRM could not be applied successfully.

I didn’t bother reading any instructions before installing and when prompted to enter the server, I entered:

http://crmtest/OrgName

I solved the problem by removing the “/OrgName” from the URL I had entered.  From there, everything was fine.

Tags: ,


Random Error Message: Entity Relationship Was Not Found in the Metadata

I was recently working with MS CRM using the Advanced Developer Extensions that were introduced in CRM Update Rollup 12.  Others have blogged about the extensions and the basics so I won’t cover them here.  I do want to mention an error that I encountered and was able to get down to the root cause of the issue (with a lot of persistence).  First, the error message:

0x8004024a
Entity Relationship <relationship name> was not found in the metadata
Platform

I encountered this and actually found something on a forum posting and finally have some time to revisit this in more detail.  The original poster was encountering the error while using the traditional MS CRM web services while I encountered it using the advanced developer extensions.  I posted that as a reply and promised to dig in more when time permitted.  What I’ve found is interesting: I can’t reproduce the error using the web services like the poster in the forum but I can reproduce it using the advanced developer extensions.

What I was attempting to do was create a many-to-many relationship between the two entities.  For the example I’ll use the contact entity, which has a many-to-many relationship with the custom entity new_professionalorganization.  A contact can belong to many professional organizations and a professional organization can have many contacts.  In my real project, in the “Relationship Definition” section of the many-to-many relationship, the “Name” did not match the “Relationship Entity Name”.  This is the root cause of the problem: when using the advanced developer extensions to create a many-to-many relationship, the “Name” must be the same as the “Relationship Entity Name”.  If they don’t, you will receive the above error and your relationship will not be created.

Here is a screen shot of what it takes when naming your relationship to have it break.  If you want it to work, make sure both the “Name” and “Relationship Entity Name” have the same value.

CRM Relationship Definition

If you want to reproduce the error, do the following.  The steps are not overly detailed and they assume you have basic knowledge of customization in CRM as well as using the advanced developer extensions.  The links above should help if you are new to using the advanced developer extensions.

  1. In Settings–>Customization, create a new entity and call it “Professional Organization”.  Don’t worry about adding any attributes – just use the default ones.  Have the entity show up in CRM wherever you like.
  2. In CRM, create a new Professional Organization.
  3. Open the contact entity and select “N:N Relationships”.
  4. Create a new N:N relationship with contact as the “Current Entity” and for the “Other Entity” select the newly create “Professional Organization”.
  5. For the “Display Option” on both entities, select “Use Plural Name”.
  6. For the “Name” value in the “Relationship Definition” section, change it from the default value to new_contact_new_proforg”.  Leave the and “Relationship Entity Name” as the default value of “new_contact_new_professionalorganization”.
  7. Click Save and publish your customizations.
  8. Using the crmsvcutil, generate your Xrm classes and add them to a .Net project.
  9. Create a relationship between a contact and a professional organization.  The code may look similar to the snippet below that creates a relationship.

DataContext ctx = new DataContext("TestOrg");

contact contact =

(from c in ctx.contacts where c.fullname == "Chuck Finley"select c).FirstOrDefault();

new_professionalorganization professionalOrg =

          (from o in ctx.new_professionalorganizations where o.new_name == "Microsoft Certified Professionals" select o).FirstOrDefault();

ctx.AddLink(contact, "new_contact_new_proforg", professionalOrg);

ctx.SaveChanges();

When you run your app with code similar to the snippet above (you’ll need to set up the data, your data context, etc.), you should encounter the error mentioned above.  If you repeat the above steps but set the “Name” and “Relationship Entity Name” (step 5) to the same value (doesn’t matter what you change it to, as long as they match), you will successfully create the relationship.  Don’t forget step 8 where the CRM classes are generated or you won’t see the issue.

Hopefully this will help someone when they encounter this error.  It can obviously be worked around by using the same name/relationship entity name, so in the grand scheme of things it’s not huge – it’s just a real pain when you don’t know what the root cause of the issue is and you just want things to work!

Tags:


MS CRM Advanced Developer Extensions Error

I’ve been doing quite a bit of work lately with the Microsoft CRM SDK and taking advantage of the Advanced Developer Extensions. Here’s a quick introduction to what they are and what you can do. It definitely makes building applications against MS CRM easier.

I had a situation recently where I was inserting and account and a contact associated with that account. I was creating the account, calling the AddToaccounts method, creating the associated contact, calling the “AddTocontacts” method and then calling the “SaveChanges()” method, but it failed with the error message “Account With Id = 00000000-0000-0000-0000-000000000000 Does Not Exist”. The broken code looked something like this (I just wrote this but didn’t compile it, but it should be close):

accoount newAcc = new account();
newAcc.name = "Test Account";
newAcc.address1_line1 = "123 Main Street";
// ... Add more fields ...
// Add to list of pending changes
ctx.AddToaccounts(newAcc);

contact newCon = new contact();
newCon.firstname = "Jeff";
newCon.lastname = "Ballard";
// ... Add more fields ...
// Add to list of pending changes
ctx.AddTocontacts(newCon);

newCon.contact_customer_accounts_id = newAcc.accountid

ctx.SaveChanges();

The fix was fairly simple. Right after the account declaration, assign the account id manually instead of letting CRM do it for you. The updated code would look like this:

accoount newAcc = new account();
/*****  Add the next line to make sure the account id is populated.  *****/
newAcc.accountid = Guid.NewGuid();
/*****  Add the above line to make sure the account id is populated.  *****/
newAcc.name = "Test Account";
newAcc.address1_line1 = "123 Main Street";
// ... Add more fields ...
// Add to list of pending changes
ctx.AddToaccounts(newAcc);

contact newCon = new contact();
newCon.firstname = "Jeff";
newCon.lastname = "Ballard";
// ... Add more fields ...
// Add to list of pending changes
ctx.AddTocontacts(newCon);

newCon.contact_customer_accounts_id = newAcc.accountid

ctx.SaveChanges();

There is a second way to make it work. You can leave out the line added above and instead add:

ctx.SaveChanges();

after the line:

ctx.AddToAccounts(newAcc);

The first method forces the account id to be populated in your code, the second populates the accountid with the value returned after the record is inserted. Either way works – it just depends on preference.

Tags: , ,