我正在探索用于通过Dynamics CRM SDK检索数据的“QueryExpression”机制,我认为我已经遇到了SDK的问题/限制,但我想确定这一点......
鉴于这个理想的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'
我似乎无法将上述过滤条件(where子句)转换为等效的SDK条件/ filterexpressions等。
如您所见,我想查询: -
所以我在上面第3点描述的问题意味着我无法查询动态:
这是SDK的当前限制吗?
答案 0 :(得分:5)
好的,我已经找到了答案,部分归功于@mwrichardsone,他促使我探索Dynamics Crm Linq查询提供程序如何做到这一点,然后我就可以从那里向后工作..
所以这里是等效的Linq查询表达式(我正在使用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;
然后我发现这篇文章解释了如何将linq查询转换为Query Expression或Fetch Xml:http://pogo69.wordpress.com/2012/04/05/crm-linq-provider-converting-expressions-to-queryexpression-andor-fetchxml/
一旦我应用了这种技术,我就能看到等效的QueryExpression看起来像什么......基本上,我缺少的那一点(关键洞察力)是当你添加一个ConditionExpression时你可以设置它的“EntityName”。这意味着您可以将ConditionExpression添加到父/主实体上的过滤器组,即使该条件实际上是针对链接实体上存在的属性(在本例中为customeraddrress line1)。我假设你必须将条件添加到具有该特定属性的linkentity中 - 这也是@Henk van Boeijen在他的答案中所做的 - 并且没有给出正确的结果。
所以最终工作的QueryExpression看起来像这样(注意地址行1的条件没有添加到地址链接实体,它被添加到主实体上的过滤器组,并且它有一个“实体名称”设置为链接实体的别名)
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..");
}
附注:如果您希望查看构建查询表达式的更短语法,请参阅下面的@Henk van Boeijen的帖子。如果生产力确实是您真正关心的问题,我将不得不回应下面@Nicknow的评论,并建议您认真考虑使用Linq查询机制来执行CRM查询。
@Henk van Boeijen也指出我的答案是基于仅出现在2013 SDK中的功能,并且似乎不在以前的版本中。我没有亲自检查过,但是如果你没有使用最新版本的SDK,那么这些信息对你来说可能非常有用。
答案 1 :(得分:1)
实际上非常简单;使用LogicalOperator和LinkEntity。
我建议添加DISTINCT谓词。
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;
}
请务必注意,此查询使用Dynamics CRM 2013中添加的新功能。它在Dynamics CRM 2011中不起作用,因为在该版本中,无法在{}中指定实体名称(或其别名) {1}}。