FetchXml vs. QueryExpression
“FetchXml vs. QueryExpression, which should I use?” seems to be a question every new Microsoft Crm 2011 developer asks. Depending on who you’ll ask, you’ll get wildly disparate responses and ones that seem pretty definitive. Developers who have been doing MSCRM development for a while tend to advocate using FetchXml from what I can see. I surmise this has something to do with the fact FetchXml has been around the longest and now. Furthermore in MSCRM 2011, you can actually build your query visually and have the FetchXml output generated for you (see below):
Additionally, back when MSCRM 4.0 was out and this feature was not available, Stunnware had a really handy FetchXml generator which let you visually construct queries. I’ve heard all sorts of other bits of conventional wisdom but the more I dug into the veracity of these claims (like “It’s much faster”) the less I was able to verify them (the MSCRM 4.0 documentation indicates that QueryExpression is faster b/c it doesn’t need to be parsed, but I’ve heard a few vets swear the opposite is true). I’m not saying they’re not true, just saying that particularly when using MSCRM Online, I haven’t been able to see much of a difference one way or the other in terms of performance [Actually, it's probably more precise to say that too many other factors come into play that make it really hard to isolate things down to this level).
Using the QueryExpression class seems a little more modern, a little more Object Oriented if you will and b/c you get intellisense support, seems to be a little more precise but each of these reasons is subjective (other than the Intellisense part). As I just said though, 'precise' is in the eye of the beholder (if you're getting a FetchXml query back from MSCRM, there's no real issue with precision other than perhaps if you made a copy/paste error) and you're more like to make a mistake using a hand-generate QueryExpression instance.
The one area I"ve been able to detect that FetchXml has an advantage over QueryExperssion is in terms of Aggregates. At least as far as I know, if you need to use an aggregate expression, such as Sum, Count or Average, there is no direct implementation in the QueryExpression class. If you use the OrganizationServiceContext and go with the Entity Approach, you can certainly use LINQ semantics to generate aggregates in your code. Somewhere along the lines the aggregates are getting translated to SQL and my point here was trying to get to the bottom of how things worked.
There is one message and one method that can translate FetchXml to a QueryExpression and a QueryExpression to FetchXml. Unsurprisingly, they're named the FetchXmlToQueryExpressionRequest / FetchXmlToQueryExpressionResponse and the QueryExpressionToFetchXmlRequest and QueryExpressionToFetchXmlResponse. So I wanted to do a little digging. Here's what I did. I started off with a basic Aggregate Expression in FetchXml (taking the code straight from the SDK on computing an Average for the EstimatedValue property of an Opportunity). When I passed this in to the RetrieveMultiple method of the OrganizationService, I noticed that I always got back exactly on Entity. Using the AliasedValue class (Microsoft.Xrm.Sdk.AliasedValue) I noticed that the aliased field contained the computed aggregate. Nothing earth shattering there, and exactly what I expected.
CrmConnection Connection = new CrmConnection("CrmMain"); IOrganizationService Service = new OrganizationService(Connection); String Estimatedvalue = @"<fetch distinct='false' mapping='logical' aggregate='true'><entity name='opportunity'><attribute name='estimatedvalue' alias='estimatedvalue_avg' aggregate='avg' /> </entity></fetch>"; FetchExpression FetchQuery = new FetchExpression(Estimatedvalue); EntityCollection Results = Service.RetrieveMultiple(FetchQuery); if(null != Results && Results.Entities.Count > 0){ Console.WriteLine("Average: {0}", ((Money)((AliasedValue)Results[0]["estimatedvalue_avg"]).Value).Value); }
Now, I tried using the same FetchXml expression in conjunction with the OrganizationService 's FetchXmlToQueryExpression extension method.
FetchXmlToQueryExpressionRequest ConversionRequest = new FetchXmlToQueryExpressionRequest(); QueryExpression ConversionResponse = Service.FetchXmlToQueryExpression(Estimatedvalue) as QueryExpression ; EntityCollection QueryExpressionResults = Service.RetrieveMultiple(ConversionResponse); foreach (Entity queryExpressionResult in QueryExpressionResults.Entities) { Console.WriteLine("Opportunityid:{0}", queryExpressionResult["opportunityid"].ToString()); } Console.WriteLine("Total Opportunities from Converted QueryExpression: {0}", QueryExpressionResults.Entities.Count.ToString());
What I got back was a little surprising:
Notice that now, I got back exactly 15 entities (this happens to be the exact # of Total Opportunities, both open and closed). There was only one field and the QueryExpression didn't have much to it other than the EntityName.
So I decided to do the exact same thing, just in reverse (using teh QueryExpressionToFetchXmlRequest and QueryExpressionToFetchXmlResponse messages). And what I got back makes sense, but I was a little surprised (see above). I got back the exact same items in the exact same order, same count same everything. Why was I surprised and what did this say? Well, I was sort of expecting to see some magic computation going on, thinking that maybe something was being done in the FetchXml request that simply wasn't publicly exposed in the QueryExpression class. But no, that didn't happen. B/c I'm using CrmOnline, I wasn't able to run profiler and see exactly what Query is being generated, but I have a strong suspicion that when FetchXml is used directly, it does actually fire a SELECT AVERAGE(FIELD) FROM TABLE in Sql (the SDK code comments imply as much). That's b/c we only get one value back from the original query. When we run it either of the other two ways , using QueryExpressionToFetchXmlRequest or FetchXmlToQueryExpression, b/c there's no direct aggregate operator in a QueryExpression, you get back all of the corresponding records. To simulate an aggregate, you'd need to iterate through the collection and run the aggregate on your own. At this point that's my suspicion, but looks like some more investigation is in order when I can use a OnPrem instance of MSCRM and see exactly what's happening behind the scenes.
For now, I'll have to say I'm taking a middle of the road approach. I prefer using the QueryExpression class for *Most* things b/c personally I know it better and think it's a little cleaner- but let me emphasize as strongly as possible, that's just *my* opinion. I say 'Most' b/c if there's an aggregate, it seems more straightforward to just build a FetchXml aggregate expression and use it.
If you're interested, here are a few discussions lingering around the web on the issue:
- FetchXml vs QueryExpression
- Using FetchXml
- FetchXml v/s QueryExpression
- Difference between FetchXml and QueryExpression
- Converting Expressions to QueryExpression
If you have any questions or comments, leave them in the post or contact our team at devteam@dynamics4.com
————————————————————–
KeyWords: Dynamics4.com, Microsoft.Xrm.Sdk.Entity, Dynamics CRM 2011, RelatedEntities, LinkEntity, LinkEntities, CrmConnection, OrganizationService, FilterExpression, QueryExpression, Criteria, ,ColumnSet, FetchXmlToQueryExpressionResponse , FetchXmlToQueryExpressionRequest , QueryExpressionToFetchXmlRequest , QueryExpressionToFetchXmlResponse,FetchXml, Dynamics4, CRM South East, Atlanta, Greenville, Miami
The post FetchXml vs. QueryExpression appeared first on dynamics four.