Friday, April 22, 2011

LINQ to XSD with FetchXML

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.
01<fetch mapping='logical'>
02 <entity name='account'><all -attributes/>
03    <link -entity name='systemuser' to='owninguser'>
04 <filter type='and'>
05 <condition attribute = 'lastname' operator='eq'
06 value='crmlastname'/>
07 </filter>
08 <filter type='or'>
09 <condition attribute='firstname' operator='eq'
10 value='crmfirstname'/>
11 <condition attribute='nickname' operator='eq'
12 value='crmnickname'/>
13 </filter>
14 </link>
15 </entity>
16</fetch>
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.
1XDocument xDoc = XDocument.Load(@"..\..\sample fetch xml.xml");
2var conditions = from fe in xDoc.Elements("fetch")
3                 from e in fe.Elements("entity")
4                 from le in e.Elements("link-entity")
5                 from f in le.Elements("filter")
6                     where f.Attribute("type").Value == "or"
7                 from c in f.Elements("condition")
8                 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…
1fetch fetch = fetch.Load(@"..\..\sample fetch xml.xml");
2var conditions = from e in fetch.entity
3                 from le in e.linkentity
4                 from f in le.filter where f.type=="or"
5                 from c in f.condition
6                 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.
01// assuming we don't know what the structure of the xml is like, we use XRoot
02var xroot = XRoot.Load(@"..\..\sample fetch xml.xml");
03 
04// find the <fetch> element nodes in the xml
05var nodes = xroot.XDocument.Descendants("fetch");
06 
07if (nodes!= null && nodes.Count() > 0)
08{
09 //find all condition elements
10 var conditions = ((fetch)nodes.First()).Untyped.Descendants("condition");
11}
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.
01var fetch = new fetch {
02    mapping = "logical",
03    entity = new entity[] {
04                  new entity {
05                      name="account",
06                      allattributes = new allattributes[] { new allattributes() },
07                      linkentity = new linkentity[] {
08                        new linkentity {
09                            name="systemuser",
10                            to="owinguser",
11                            filter = new filter[] {
12                                new filter {
13                                    type="and",
14                                    condition = new condition[] {
15                                        new condition {
16                                            attribute="lastname",
17                                            @operator="eq",
18                                            value1 = "crmlastname"
19                                        }
20                                    },
21                                },
22                                new filter {
23                                    type="or",
24                                    condition = new condition[] {
25                                        new condition {
26                                            attribute="firstname",
27                                            @operator="pp",
28                                            value1 = "crmfirstname"
29                                        },
30                                        new condition {
31                                            attribute="nickname",
32                                            @operator="eq",
33                                            value1 = "crmnickname"
34                                        },
35                                    }
36                                }
37                            },
38                        }
39                      },
40                  },
41                }
42};
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).

No comments:

Post a Comment