Argos
Phil's CRM Blog | FetchXML

Generics with CRM

by Phil Adams 11. January 2010 23:26

 

Generics is a very nice feature of the C# and VB.NET language, and can be used to simplify the CRM Web Service method calls. One of my responsibilities is to develop a framework for CRM development, and one of the main classes in this framework is called CrmSystem, it wraps the CrmService methods among other things. Using generics one can then type,

C#
account acc = CrmSystem.Retrieve<account>(myAccountId);

VB
Dim acc As account = CrmSystem.Retrieve(Of account)(myAccountId)

also we use a special NameValue class CrmConditions to one of our Execute overloads, here is how it can look

C#
List<account> acc = CrmSystem.Execute<account>(new CrmCondition("emailaddress1", me@someone.com));

VB
Dim acc As List(Of account) = CrmSystem.Execute(Of account)(New CrmCondition("emailaddress1", "me@someone.com"))

This would retrieve all accounts that got the email "me@someone.com"

Here is one of the overloads for the Retrive Method that uses Generics, it calls an other overload that does the actual call to CRM Web Service using the EntityName string that we get thru typeof(T).Name

C#
public T Retrieve<T>(Guid id, params string[] columnSet) where T : BusinessEntity {
     return (T)Retrieve(typeof(T).Name, id, new ColumnSet(columnSet));
}

VB
Public Function Retrieve(Of T As BusinessEntity)(ByVal id As Guid, ByVal ParamArray columnSet As String()) As T
    Return DirectCast(Retrieve(GetType(T).Name, id, New ColumnSet(columnSet)), T)
End Function

Hope this gives some inspiration for your own CrmApi wrappers :)

Generics with CRM

Tags:

CRM | Custom Controls | FetchXML | MSCRM | mscrm4

Retrieving All Records with Fetch XML

by Phil Adams 19. March 2009 12:18

You may or may not be aware that when retrieving records from the CRM service using the Fetch() method, CRM will limit the results to the first 5000 records by default. I found a nice post by Ronald Lemmen on fetching all records, but I wanted to take his concept a step further by having a function do the following:

Accept fetch xml  in a string format
Add the paging functionality to fetch all records
Merge the results together
Return the merged results in a string format
I like this approach because it uses no extraneous data types, the fetch xml is passed as a parameter (no hard-coding of your fetch unless you want to!), and the returned xml is identical to what the Fetch() method would return (except more records are there, of course).

The Standard Fetch
The normal usage of the Fetch() method would be like this:

string sFetchXml = "<fetch xml goes here>";
string sResultsXml = service.Fetch(sFetchXml);

You would probably just load your results xml into an XmlDocument object and work with the data in that fashion. If there are more than 5000 records, you'd have to perform another fetch to retrieve additional records 5000 at a time.

Let's instead create a private function that handles all of this for us.

fetchAll()
First things first, let's declare the function. We want it to accept the fetch xml and return the results xml.

private string fetchAll(string sFetchXml)

Logic within the function will handle the paging. We do it by utilizing a boolean flag to determine whether we have to perform any more fetches. Also we'll create an XmlDocument object to store our results that will eventually be returned:

bool bComplete = false;
int iPage = 1;
XmlDocument oResults = new XmlDocument();
while (!bComplete)
{

...

}

So, while bComplete evaluates to false, we're first going to load the fetch xml into an XmlDocument object. Then we'll grab the <fetch> node and see if it has a page attribute. If it doesn't, we'll add it. We set the page attribute to the value of iPage.

XmlDocument oFetchXml = new XmlDocument();
oFetchXml.LoadXml(sFetchXml);
XmlNode oFetchNode = oFetchXml.SelectSingleNode("/fetch");
if (oFetchNode.Attributes["page"] == null)
{
    XmlAttribute oPageAttribute = oFetchXml.CreateAttribute("page");
    oPageAttribute.Value = iPage.ToString();
    oFetchNode.Attributes.Append(oPageAttribute);
}
else
{
    oFetchNode.Attributes["page"].Value = iPage.ToString();
}

The above code automatically tweaks our fetch xml to enable us to perform subsequent fetches. Next, we'll perform the fetch and load our results into a temporary XmlDocument object (I'm assuming you already have a CrmService object created and have named it oService):

string sResultsXml = oService.Fetch(oFetchXml.InnerXml);
XmlDocument oTempXml = new XmlDocument();
oTempXml.LoadXml(sResultsXml);

Next, we've got to add our fetch results to the oResults xml object:

if (iPage == 1)
{
    oResults.LoadXml(oTempXml.InnerXml);
}
else
{
    XmlNodeList oNodes = oTempXml.SelectNodes("/resultset/result");
    XmlNode oResultsetNode = oResults.SelectSingleNode("/resultset");
    foreach(XmlNode oNode in oNodes)
    {
        XmlNode oNewNode = oResults.ImportNode(oNode,true);
        oResultsetNode.AppendChild(oNewNode);
    }
}

Now we have handled our fetch xml and merging the resulting records. Now we need to figure out if we have any additional fetches to perform by checking the morerecords attribute of the resultset node. If we have more records, we just incrcement the iPage variable, otherwise, set bComplete to true.

XmlNode oMore = oTempXml.SelectSingleNode("/resultset");
if (oMore.Attributes["morerecords"].Value == "0")
{
    bComplete = true;
}
else
{
    iPage++;
}

That's the meat of the function right there. All we have to do now is return the data in our oResults object (remember, this would be after our while loop):

return oResults.InnerXml;

Hopefully, you'll find this function to be extremely useful in situations where you have a lot of records. Best of all, it's easily re-used.

Tags:

FetchXML | CRM | MSCRM | mscrm4

About Phil

Phil has been working with CRM since the BETA of CRM v1.0 and has seen a lot of the problems arising from installation, maintenance and Development.

Phil specializes in the ISV area of CRM; Creating Add-Ons and Plugins for various clients.

Phil currently works as a Microsoft Dynamics CRM Consultant and Developer for Cambridge Online Systems Ltd In the UK.

Phil also has several Microsoft Certifications in .NET and CRM