如何在CRM中执行相对补充查询?

时间:2012-11-16 16:08:30

标签: dynamics-crm-2011 fetchxml query-expressions

背景(即什么是相对补充?)

Relative Complement

我正在尝试做什么

假设我有一个自定义Vehicle实体,其VehicleType选项设置为“Car”或“Truck”。联系人和车辆之间存在1对多的关系(即,ContactId在车辆实体上)。如何编写一个XRM查询(Linq To CRM,QueryExpression,获取Xml,等等),只返回只有汽车的联系人?

Relative Complement Venn Diagram

4 个答案:

答案 0 :(得分:1)

选项1:

我更喜欢修改AdamV在上面提出的提案。我想不出一种方法,你可以使用Linq to CRM,Query Expressions,FetchXML单独回答这个特定的查询。 Daryl不提供客户端,但我想如果Linq和Query Expressions是可接受的产品,.NET就在桌面上。在父实体上创建包含相关实体计数的聚合字段(在本例中为contact)提供的不仅仅是Boolean选项。如果查询要求曾经更改为阈值(超过X辆车,少于Y辆卡车,X和Y车辆总数之间),则布尔选项无法提供。这个问题中的客户端是未知的,但是我想不出很多(任何?)的情况,在一组500K +行上将所有记录拉到客户端比CRM可以做的SQL查询更有效代表您使用范围子句的几个整数字段。

上行:

  1. 在查询方法中维护客户端纯度
  2. 简单客户端查询
  3. 可能尽可能高效
  4. 缺点:

    1. 汇总字段的设置
    2. 用于管理聚合字段的增量和减量的工作流程或插件
    3. 用于初始加载聚合的SQL脚本。
    4. 聚合字段不同步的风险(工作流程或插件失败)
    5. 选项2:

      如果客户端内的纯度不是必需的,并且.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. 工作少得多
      2. CRM实体独自留下
      3. 缺点:

        1. 根据客户端和/或应用程序的不同,混合使用DataAccess方法有点麻烦。
        2. 可能性低于选项1
        3. 选项3:

          混合和匹配:从选项1获取聚合字段。但是使用预定的SQL作业(或类似的)更新它们,其查询类似于您需要在选项1中编写的初始加载作业

          上行:

          1. 从选项1
          2. 中完成大部分工作和风险
          3. 保留选项1的所有表现
          4. 缺点:

            1. 有些人会将此视为不受支持的功能。

答案 1 :(得分:1)

为了执行真正的相对补充查询,您需要能够执行子查询。

您的查询基本上会说给我所有与汽车的联系人,然后,在这些结果中,删除任何车辆不是汽车的联系人。这就是@JasonKoopmans中的SQL所做的回答。不幸的是,CRM does not support SubQueries

因此,实现此目的的唯一方法是在客户端执行子查询,因为我采取行动,或者以可以通过主查询访问的方式存储子查询的结果(即在联系实体上存储计数)。

理论上,您可以通过创建一个存储SubQueryResultContactId的{​​{1}}实体来“即时”执行此操作。您首先撤回至少有1个汽车的联系人,并为每个记录创建一个SubQueryResult记录,使用它的contactId,以及生成客户端的单个SubQueryId将它们绑定在一起。

然后你会做另一个查询,告诉我这个SubQueryResult中的所有联系人都使用这个SubQueryId,没有任何车辆不是汽车。

我只能假设这不会比执行两个单独的查询和执行过滤器客户端更有效。虽然在新的CRM版本中使用新的ExecuteMultipleRequests,但它可能很接近。

答案 2 :(得分:0)

由于CRM 2011不通过查询表达式支持,因此我已经撤回了我在CRM中的所有记录,并在客户端执行检查。

您可以编写两个Fetch XML语句,一个用于返回所有联系人及其车辆的计数,另一个用于返回所有联系人及其车辆的计数,然后比较客户端的列表。但是,再一次,你必须返回每个联系人并过滤它的客户端。

答案 3 :(得分:0)

它没有经过测试,但这个查询表达式怎么样?我将 Vehicle 实体中的链接作为内部联接,要求它是 Car 。我假设字段 VehicleType 是一个 String ,因为我有点懒,不想测试它(我正在输入这个硬核风格,没有编译 - 纯脑力工作)。

或者,您可能还需要添加条件部分,以控制实际获取的 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 的新实例时,都需要触发消息并使用插件,首先更新有关创建后者的信息。

这有几个缺点。

  1. 这要求我们做点什么。
  2. 这不是直截了当的做 - 这种和那种方法。
  3. 每增加一种新型 Vehicle ,维护费用会更高。
  4. 由于有许多情况需要考虑(当重新分配,删除等 Vehicle 实例时,标志化会发生什么情况),因此可提升性提升。
  5. 所以,我对你问题的回答改为:“无法完成”。这一点仍然有效,直到(很高兴)通过提出的替代解决方案证明是错鸭!

    就个人而言,我会抓取(差不多)一切并将LINQ的猎犬释放到它上面。但我不会微笑也不会自豪。 :)