LINQ to XSD with FetchXML

Recently I’ve been playing with MS CRM Dynamics 4.0 at work, and had to do some XML manipulation with FetchXml. There’s a new set of XML API in the namespace System.Xml.Linq (more commonly known as LINQ to XML) which is pretty powerful, but what I dislike about it is that it’s not strongly typed. When you create or manipulate something like FetchXml, you need to know the structure, rules and restrictions based on the schema in order to ensure your XML is valid. How do we do that??

I have played with LINQ for a while, and there’s now LINQ to almost everything. Indeed, I found LINQ to XSD, and decided to see if it can fit my expectation. I’m not going to go into the steps of installing and setting it up on VS2008, you can download the installer for LINQ to XSD and the overview document as DIY exercise.

First off, you can get a copy of FetchXml Schema here. Once you’ve installed the package, here are quick steps to create a LINQ to XSD project. (Or use the overview document for detailed steps.)

  1. In VS2008, create a new Console App under project type “LINQ to XSD Preview
  2. Add a new Schema document into your project. (.xsd file)
  3. Copy and paste the FetchXml Schema into your newly create XSD document.
  4. Select Properties of the Schema, under Build Action, select LinqToXsdSchema.
  5. Build your solution, and you now have strongly typed XML mapping objects. (Open Object Browser[Ctrl +W, J] and you can see these new classes)

This is a typical sample of FetchXml.

<fetch mapping='logical'>
 <entity name='account'><all -attributes/>
	<link -entity name='systemuser' to='owninguser'>
 <filter type='and'>
 <condition attribute = 'lastname' operator='eq'
 <filter type='or'>
 <condition attribute='firstname' operator='eq'
 <condition attribute='nickname' operator='eq'

For example, you needed to look for all children <condition> nodes where the parent node is <filter type=’or’>, you can use XDocument class to do something like this.

XDocument xDoc = XDocument.Load(@"..\..\sample fetch xml.xml");
var conditions = from fe in xDoc.Elements("fetch")
                 from e in fe.Elements("entity")
                 from le in e.Elements("link-entity")
                 from f in le.Elements("filter")
                     where f.Attribute("type").Value == "or"
                 from c in f.Elements("condition")
                 select c;

There’s nothing wrong with this approach, except that it can be error prone. With LINQ to XSD, you get a object mapping to XML in a typed manner and provides a pleasant OO programming style for developers. There’s two approaches to query and we’ll be looking at Typed Query first.

Typed Query

The above LINQ to XML Query can now be structured using LINQ to XSD like so…

fetch fetch = fetch.Load(@"..\..\sample fetch xml.xml");
var conditions = from e in fetch.entity
                 from le in e.linkentity
                 from f in le.filter where f.type=="or"
                 from c in f.condition
                 select c;

Typed XML is made possible and makes it much easier to program against. Code is cleaner, easier to maintain, and breaking-changes can be found at compile time when we change the schema and rebuild the solution.

UnTyped Query

There will be times when you get an unfamiliar XML and need to do a ‘blind’ query. In situations like this, you can use the XRoot class in the LINQ to XSD library, and then look for elements you want, using the UnTyped property.

// assuming we don't know what the structure of the xml is like, we use XRoot
var xroot = XRoot.Load(@"..\..\sample fetch xml.xml");

// find the <fetch> element nodes in the xml
var nodes = xroot.XDocument.Descendants("fetch");

if (nodes!= null && nodes.Count() > 0)
 //find all condition elements
 var conditions = ((fetch)nodes.First()).Untyped.Descendants("condition");

Create Typed XML

Lastly I want to show you how easy it is to create an XML using this Typed-XML approach, using C# object initializer syntax. Of course you could do it in an imperative style, but I prefer the former (I’m weird). The code below creates the sample FetchXml shown in the snippet earlier.

var fetch = new fetch {
    mapping = "logical",
    entity = new entity[] {
                  new entity {
                      allattributes = new allattributes[] { new allattributes() },
                      linkentity = new linkentity[] {
                        new linkentity {
                            filter = new filter[] {
                                new filter {
                                    condition = new condition[] {
                                        new condition {
                                            value1 = "crmlastname"
                                new filter {
                                    condition = new condition[] {
                                        new condition {
                                            value1 = "crmfirstname"
                                        new condition {
                                            value1 = "crmnickname"

I really like the Typed-XML syntax you get out of LINQ to XSD. It makes programming against XML easier and simply more enjoyable. Greatest benefits are the elimination of mis-spelling of element/attribute names, data-type constraint checks and casting validation. However at this point, there’s no real full-validation support against the entire schema and I hope this will be a feature added in next release (if there’s one).

Also check out this great article on how to use CRM Advanced Find to build your FetchXml.

Download code sample here. (remember to install the LINQ to XSD package first)

Share this post:

Leave a Reply

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

You are commenting using your 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

%d bloggers like this: