Microsoft Dynamics Crm Sdk - Is this query possible?

匿名 (未验证) 提交于 2019-12-03 07:50:05

问题:

I am exploring the "QueryExpression" mechanism used to Retrieve data via the Dynamics CRM SDK, and I think I have hit a problem / limitiation with the SDK, but I would like to ascertain that for certain..

Given this desired SQL:

Select C.firstname, C.lastname  FROM contact C  INNER JOIN customeraddress A on C.contactid = A.parentid WHERE  ((C.firstname = 'Max' AND C.lastname = 'Planck') OR (C.firstname = 'Albert' AND C.lastname = 'Einstein')) OR  A.Line1 = 'The secret moonbase' 

I cannot appear to translate the filter criteria above (the where clause) into the equivalent SDK conditions / filterexpressions etc.

As you can see, I want to query:-

  1. contact, joined to customeraddress (thats simple, just add a link entity to the query expression),
  2. where the contact is either Albert Einstein, or Max Planck (Again, that is simple, add FilterExpressions to the QueryExpression)
  3. OR the customeraddress 'line1' equals 'the secret moonbase' (This is the problematic bit, as soon as I append filter criteria to the LinkEntity, Dynamics uses an "AND" conjunction with the criteria / filters on the main entity.

So the problem I have described in point 3 above, means I can't query dynamics for:

  1. (Albert Einstein Or Max Planck) or anyone who lives at the secret moonbase.

Is this is a current limtation of the SDK?

回答1:

Ok, I have discovered the answer to this, thanks in part to @mwrichardsone who prompted me to explore how the Dynamics Crm Linq query provider does it, I was then able to work backwards from there..

So here is the equivalent Linq query expression which works (I am using the CrmOrganisationServiceContext):-

var contactsQuery = from c in orgService.CreateQuery("contact")                     join a in orgService.CreateQuery("customeraddress") on (Guid)c["contactid"] equals (Guid)a["parentid"]                                 where (((string)c["firstname"] == "Max" && (string)c["lastname"] == "Planck")                                 || ((string)c["firstname"] == "Albert" && (string)c["lastname"] == "Einstein"))                                 || (string)a["line1"] == "The secret moonbase"                     select c; 

I then found this article which explains how you can convert linq query to a Query Expression or Fetch Xml: http://pogo69.wordpress.com/2012/04/05/crm-linq-provider-converting-expressions-to-queryexpression-andor-fetchxml/

Once i applied that technique I was able to see what the equivalent QueryExpression looks like.. and basically, the bit that I was missing (key insight) is that when you add a ConditionExpression you can set it's "EntityName". This means you can add a ConditionExpression to a filter group thats on the parent / main entity, even though the condition is actually for an attribute thats present on a link entity (in this case customeraddrress line1). I was assuming you had to add the condition to the linkentity that had that particular attribute - which is also what @Henk van Boeijen did in his answer - and that did not give the correct results.

So the final working QueryExpression looks like this (notice the condition for address line 1 is not added to the address link entity, its added to the filter group on the main entity, and it has an "entity name" set to the alias of the link entity)

var orgService = serviceProvider.GetOrganisationService();         using (orgService as IDisposable)         {              var query = new QueryExpression("contact");             query.ColumnSet.AddColumn("firstname");             query.ColumnSet.AddColumn("lastname");              // so link in customer address.             query.AddLink("customeraddress", "contactid", "parentid", JoinOperator.Inner);             var addressLink = query.LinkEntities[0];             addressLink.EntityAlias = "A";             addressLink.IncludeAllColumns();              // conditions for max planck             var firstName1Condition = new ConditionExpression("firstname", ConditionOperator.Equal, "Max");             var lastname1Condition = new ConditionExpression("lastname", ConditionOperator.Equal, "Planck");              // Groups those conditions using an "AND" conjunction.             var maxPlankFilter = new FilterExpression(LogicalOperator.And);             maxPlankFilter.AddCondition(firstName1Condition);             maxPlankFilter.AddCondition(lastname1Condition);              // conditions for albert einstein             var firstname2Condition = new ConditionExpression("firstname", ConditionOperator.Equal, "Albert");             var lastname2Condition = new ConditionExpression("lastname", ConditionOperator.Equal, "Einstein");              // Groups those conditions using an "AND" conjunction.             var albertEinsteinFilter = new FilterExpression(LogicalOperator.And);             albertEinsteinFilter.AddCondition(firstname2Condition);             albertEinsteinFilter.AddCondition(lastname2Condition);              // could optionally chain the 2 filters so we get Albert's contitions chained (using AND) to max's conditions              //  albertEinsteinFilter.AddFilter(maxPlankFilter);              // conditions for address line 1 moonbase             var addressLine1Filter = new FilterExpression(LogicalOperator.And);              var line1Condition = new ConditionExpression("A", "line1", ConditionOperator.Equal, "The secret moonbase");             addressLine1Filter.AddCondition(line1Condition);               // add filters to query              // ensures each filter that we add to our queries criteria is chained together using an OR.             query.Criteria.FilterOperator = LogicalOperator.Or;             query.Criteria.AddFilter(albertEinsteinFilter);             query.Criteria.AddFilter(maxPlankFilter);             query.Criteria.AddFilter(addressLine1Filter);              var results = orgService.RetrieveMultiple(query);             int resultCount = 0;             foreach (var r in results.Entities)             {                 resultCount++;                 Console.WriteLine(string.Format("{0} {1} {2}", (string)r["firstname"], (string)r["lastname"], (string)((AliasedValue)r["A.line1"]).Value));             }             Console.WriteLine("There were " + resultCount + " results..");           } 

Side Note: See @Henk van Boeijen's post below if you would like to see a shorter syntax for building a query expression. If productivity is truly your concern however, I would have to echo the comment from @Nicknow below and suggest that you seriously take a look at using the Linq query mechanism for performing CRM queries.

Also @Henk van Boeijen has pointed out that my answer is based on a feature that only appears in the 2013 SDK, and doesn't appear to be in prior versions. I haven't checked this personally, but that information is probably very useful for you to know especially if you are not using the latest versions of the SDK.



回答2:

It is actually pretty straightforward; use the LogicalOperator and the LinkEntity.

I would recommend adding the DISTINCT predicate.

private IEnumerable<Entity> QueryExpression(IOrganizationService service) {     var query = new QueryExpression("contact");     query.Distinct = true;     query.ColumnSet.AddColumns("firstname", "lastname");      query.Criteria.FilterOperator = LogicalOperator.Or;     var f1 = query.Criteria.AddFilter(LogicalOperator.And);     f1.AddCondition("firstname", ConditionOperator.Equal, "Max");     f1.AddCondition("lastname", ConditionOperator.Equal, "Planck");      var f2 = query.Criteria.AddFilter(LogicalOperator.And);     f2.AddCondition("firstname", ConditionOperator.Equal, "Albert");     f2.AddCondition("lastname", ConditionOperator.Equal, "Einstein");      var link = query.AddLink("customeraddress", "contactid", "parentid");     link.EntityAlias = "ca";     query.Criteria.AddCondition("ca", "line1", ConditionOperator.Equal, "The secret moonbase");      var response = service.RetrieveMultiple(query);      return response.Entities; } 

It is important to note that this query uses a new feature added in Dynamics CRM 2013. It does not work in Dynamics CRM 2011, because in that version it is not possible to specify an entityname (or its alias) in the ConditionExpression.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!