背景(即到底什么是相对补充?)
我正在尝试做的事情
假设我有一个自定义Vehicle
实体,它的VehicleType
选项集是“汽车”或“卡车”。Contact 和 Vehicle 之间存在一对多的关系(即,ContactId 在车辆实体上)。如何编写只返回汽车联系人的 XRM 查询(Linq To CRM、QueryExpression、获取 Xml 等)?
假设我有一个自定义Vehicle
实体,它的VehicleType
选项集是“汽车”或“卡车”。Contact 和 Vehicle 之间存在一对多的关系(即,ContactId 在车辆实体上)。如何编写只返回汽车联系人的 XRM 查询(Linq To CRM、QueryExpression、获取 Xml 等)?
我更喜欢对 AdamV 上面提出的建议进行修改。我想不出一种方法可以单独使用 Linq to CRM、查询表达式、FetchXML 来回答这个特定的查询。Daryl 不提供客户端,但我想如果 Linq 和查询表达式是可接受的产品,.NET 就在桌面上。在父实体(本例中为联系人)上创建包含相关实体计数的聚合字段提供的不仅仅是布尔选项。如果查询要求曾经更改为阈值(多于 X 辆汽车,少于 Y 辆卡车,总车辆数介于 X 和 Y 辆之间),则布尔选项无法交付。此问题中的客户未知,
优势:
缺点:
如果客户端中的纯度不是必需的,并且 .NET 就在桌面上 - 跳过聚合字段和设置,只需针对视图运行 SQL。如果您不想使用 ADO.NET,像 Dapper、Massive 或 PetaPOCO 这样的瘦 ORM 仍然可以为您提供对象模型。正如 Andreas 在他对 OP 的第一个答案的评论中所提供的那样,在 SQL 中做这件事似乎相当微不足道。
从脑海中勾勒出一些东西:
SELECT c.*
FROM Contact
WHERE C.Contactid in (
Select contactid
FROM Vehicle v
group by v.contactid , v.type
having v.type = ‘Car’ and count(contactid) > 1
)
AND NOT IN (
Select contactid
FROM Vehicle v
group by v.contactid , v.type
having v.type <> ‘Car’ and count(contactid) > 1
)
优势:
缺点:
混合和匹配:从选项 1 中获取聚合字段。但使用计划的 SQL 作业(或类似的东西)更新它们,查询类似于您需要在选项 1 中编写的初始加载作业
优势:
缺点:
为了执行真正的相对补充查询,您需要能够执行子查询。
您的查询基本上会说给我所有与汽车的联系人,然后在这些结果中,删除所有拥有非汽车车辆的联系人。这就是@JasonKoopmans 答案中的 SQL 所做的。不幸的是,CRM 不支持 SubQueries。
因此,实现这一点的唯一方法是在客户端执行子查询,就像我采取的那样,或者以可以通过主查询访问的方式存储子查询的结果(即存储依靠联系实体)。
理论上,您可以通过创建一个存储, 和的SubQueryResult
实体来“即时”执行此操作。您首先要拉回至少有 1 辆汽车的联系人,并为每个记录创建一个 SubQueryResult 记录,它是 contactId,以及在客户端生成的单个 SubQueryId 以将它们捆绑在一起。 ContactId
SubQueryId
然后你会做另一个查询,告诉我这个 SubQueryResult 中带有这个 SubQueryId 的所有联系人,这些联系人没有任何不是汽车的车辆。
我只能假设这不会比执行两个单独的查询和执行过滤器客户端更有效。尽管使用新 CRM 版本中的新 ExecuteMultipleRequests,它可能已接近。
由于 CRM 2011 不支持通过查询表达式进行此操作,因此我已求助于撤回我在 CRM 中的所有记录,并在客户端执行检查。
您可以编写两条 Fetch XML 语句,一条返回所有联系人及其车辆数量,另一个返回所有联系人及其车辆数量,然后在客户端比较列表。但是再一次,您必须返回每个联系人并在客户端对其进行过滤。
它没有经过测试,但是这个查询表达式怎么样?我将Vehicle实体链接为内部连接,要求它是Car。我假设字段VehicleType是一个字符串,因为我有点懒,不想测试它(我正在输入这种硬核风格,没有编译 - 纯大脑工作)。
或者,您可能还想添加一个Criteria部分来控制实际检索到哪些Contact实例。一定要告诉它是怎么回事!
很抱歉冗长。我知道你喜欢简短。我的大脑在迂回时工作得更好。
new QueryExpression
{
EntityName = "contact",
ColumnSet = new ColumnSet("fullname"),
LinkEntities =
{
new LinkEntity
{
JoinOperator = JoinOperator.Inner,
LinkFromEntityName = "contact",
LinkFromAttributeName = "contactid",
LinkToEntityName = "vehicle",
LinkToAttributeName = "contactid",
Columns = new ColumnSet("vehicletype"),
EntityAlias = "Vroom",
//LinkCriteria = { Conditions =
//{
// new ConditionExpression(
// "vehicletype", ConditionOperator.Equal, "car")
//} }
LinkCriteria = { Conditions =
{
new ConditionExpression(
"vehicletype", ConditionOperator.NotEqual, "truck")
} }
}
}
};
编辑:
我已经与我的 MVP Gustaf Westerlund 进行了交谈,他建议了以下解决方法。让我强调一下,这不是您最初问题的答案。这只是解决它的一种方法。而且很麻烦。:)
因此,提示是在Contact或Person实体中添加一个标志。然后,每次创建Vehicle的新实例时,都需要触发一条消息并使用插件,更新第一个关于创建后者的信息。
这有几个缺点。
所以,我对你的问题的回答改为:“做不到”。这一直有效,直到(很高兴)被提出的替代解决方案证明是错误的。鸭子!
就个人而言,我会获取(几乎)所有东西并将 LINQ 的猎犬释放到它上面。但我不会微笑也不会骄傲。:)