2

我在 CRM 之外有一个网页,允许用户执行 CRM 查找。我需要像在普通 CRM UI 中那样使用快速搜索来过滤查找结果。

我获取所选实体/视图的 FetchXML,然后获取所选实体的快速搜索视图的 FetchXML,提取 isquickfindfields=1 的过滤器节点,将 {0} 替换为他们在搜索框中键入的内容,将修改后的节点插入选定视图的 FetchXML,并执行它。

我遇到的问题是一些快速搜索过滤器针对相关实体的 id 字段,但匹配需要针对该实体的主要名称属性。

例如,下面是帐户实体的快速搜索:

<fetch version="1.0" output-format="xml-platform" mapping="logical">
<entity name="account">
    <attribute name="name" />
    <attribute name="primarycontactid" />
    <attribute name="address1_city" />
    <attribute name="telephone1" />
    <attribute name="emailaddress1" />
    <order attribute="name" descending="false" />
    <filter type="and">
        <condition attribute="statecode" operator="eq" value="0" />
    </filter>
    <filter type="or" isquickfindfields="1">
        <condition attribute="primarycontactid" operator="like" value="{0}" />
        <condition attribute="telephone1" operator="like" value="{0}" />
        <condition attribute="emailaddress1" operator="like" value="{0}" />
        <condition attribute="accountnumber" operator="like" value="{0}" />
        <condition attribute="name" operator="like" value="{0}" />
    </filter>
    <attribute name="accountid" />
</entity>

当我插入搜索文本并执行视图时,我从 RetrieveMultiple 收到此错误:

An exception System.FormatException was thrown while trying to convert input value '%acme%' to attribute 'account.primarycontactid'. Expected type of attribute value: System.Guid. Exception raised: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).

如果我使用普通的 CRM 界面,对帐户进行查找并在快速搜索框中输入联系人的姓名,搜索会按预期工作(列出我输入的主要联系人姓名的帐户)。因此,我假设当 CRM 查询数据库时,它会“智能地”匹配实体引用的主要名称属性的非 Guid 字符串。

这是添加快速搜索过滤器的代码块(整个方法的pastebin):

if (string.IsNullOrWhiteSpace(searchString) == false)
{
    var quickSearch = CRMCache.SavedQueries.FirstOrDefault(q => q.ReturnedTypeCode == view.ReturnedTypeCode && q.QueryType == SavedQueryQueryType.QuickFindSearch);
    if (quickSearch != null)
    {
        var quickSearchXml = XElement.Parse(quickSearch.FetchXml);
        var quickSearchFilter = quickSearchXml.XPathSelectElement("//filter[@isquickfindfields=1]");
        foreach (var condition in quickSearchFilter.Elements("condition"))
        {
            condition.SetAttributeValue("value", string.Format(condition.Attribute("value").Value, "%" + searchString + "%"));
        }

        viewEntityNode.Add(quickSearchFilter);
    }
}

虽然我很好奇普通的 CRM UI 是如何处理这个问题的,但我的问题是如何动态地对查找/视图应用快速搜索过滤,以正确过滤相关实体的主要名称属性?


[编辑澄清]

快速搜索(或快速查找)是 CRM 中的一种视图类型。它定义了当用户在快速搜索框中输入文本或过滤查找时要搜索的属性。所有实体都有一个快速搜索视图,一个实体只能有一个。

匹配相关实体名称的要求来自快速搜索视图。并非所有这些都包含对实体引用的过滤器,但是当它包含过滤器时,我需要匹配名称而不是 guid。由于正常的 CRM UI 正确地将搜索字符串应用于相关实体的名称,即使快速搜索视图的 FetchXML 具有针对 id 的过滤器,我也认为 CRM 在内部处理了这种情况。显然,情况并非如此(我得到的错误表明了这一点)。所以我需要检测这种情况并做一些不同的事情,我想动态地做到这一点。

动态地,我的意思是我的代码没有一堆预定义的 FetchXML 字符串。它没有针对特定实体、视图或搜索要求进行编码;并且不需要在每次添加或更改新实体或视图时都对其进行修改。在这种情况下,“动态”可能不是一个好词,但我不知道还能叫它什么。实体/视图不可知?

我不想要这样的代码:

SearchResults ExecuteView(string entityLogicalName, string searchString)
{
    switch(entityLogicalName)
    {
        case "account":
            return searchAccounts(searchString);

        ... all other enties ...

        default:
            throw new Exception("Unknown entity type: " + entityLogicalName);
    }
}


SearchResults searchAccounts(searchString)
{
    var fetchXml = string.Format(@"
<fetch>
      <entity name=""account"">
        <link-entity name=""contact"" from=""contactid"" to=""primarycontactid"">
            <attribute name=""name"" alias=""name"" />
            <filter type=""and"">
                <condition attribute=""name"" operator=""like"" value=""%{0}%"" />
            </filter>
        </link-entity>
      </entity>
</fetch>", searchString);

    return executeSearch(fetchXml);
}

因为 CRM 中的更改(添加/删除实体、添加/删除/更新视图)需要更新代码以匹配。

4

3 回答 3

2

我不知道 CRM 是如何使用字符串来搜索 guid 的,但我怀疑它会执行一些您可能无法使用的预处理或一些后端内容。(我想如果你真的想知道你可以尝试反编译 CRM .dll,但这可能需要一段时间)。

因此,作为替代方案,我建议您进一步操作 FetchXml 的处理阶段,如果您在元数据服务的帮助下执行此操作,您应该能够在没有任何硬编码的情况下逃脱。

因此,以获取帐户为例,我认为您需要编辑 xml,以便将 id 属性name附加到其上,例如primarycontactidname. 这是 FilteredView 中数据库列的名称,我相信它可以从 FetchXml 获得。(如果这不起作用,请添加link-entity带有过滤器的名称并删除现有条件)。

所以你知道什么时候追加name我会建议:

  1. 检索快速查找视图搜索条件。
  2. 对于每个条件,使用元数据服务搜索 CRM
  3. 如果字段类型是EntityReference,则使用适当的条件更新快速查找视图搜索。
于 2013-03-13T22:27:52.990 回答
2

我投票赞成詹姆斯的答案,因为我确实认为这是您问题的正确答案。但是,总体上更好的解决方案可能是为您希望从网页中搜索的每个实体创建一个特殊的系统视图。使用命名约定,以便您的网页知道要查找的系统视图。在系统视图中,在条件字段中指定 {0},然后像往常一样在代码中替换它。通过这种方式,您可以创建所需的任何复杂 FetchXML,而无需查询元数据服务的开销。要获得奖励积分,请禁用此新系统视图,使其在 CRM UI 中不可见。

-在您的评论后添加:

快速查找实际上并不“过滤查找/视图”。当您在 CRM UI 的快速查找框中键入查询时,它不会过滤当前视图 - 使用“快速查找”视图显示结果(请参阅视图下拉菜单)。如您所见,此视图使用特殊的 FetchXML - 它使用“isquickfindfields”属性。此属性必须是 CRM UI 的标志,以在提交查询之前预处理此 FetchXML 并更新节点以更正这些关系字段的 FetchXML。

如果您的意图是在此备用 UI 中显示所有系统视图,但允许它们全部被看起来像快速查找搜索框的东西过滤,那么您所谈论的东西根本不像 CRM UI。:)

如果您只是在讨论在此备用 UI 中使用相同的快速查找视图参数,那么我的建议仍然是在 CRM 中创建一个模拟快速查找视图的隐藏系统视图。此视图后面的 FetchXML 将是“正常的”,您将能够插入搜索文本,而无需调用元数据服务。

于 2013-03-17T05:58:17.437 回答
0

我希望我理解你的问题。在这种情况下,primarycontactid 不是名称,而是代表记录的 guid,即联系人。除非您的用户知道搜索此字段的每条记录的 guid,否则没有意义。但是您想在联系人内部进行搜索,因此您必须做一个链接(相当于在 sql 中加入),请参阅此处如何使用 FetchXml 和链接实体的示例:

现在你想做一个例子:

<fetch>
      <entity name="account">
        <link-entity name="contact" from="contactid" to="primarycontactid">
            <attribute name="name" alias="name" />
            <filter ... />
        </link-entity>
      </entity>
</fetch>

在 C# 中动态执行 FetchXML:

string fetchrequest = string.Format(
@"<fetch mapping='logical' aggregate='true'>
    <entity name='queueitem'>
        <attribute name='queueitemid' alias='c' aggregate='count'/>
        <filter type='and'>
            <condition attribute='objecttypecode' operator='ne' value='4406'/>
            <condition attribute='queueid' operator='eq' value='{0}'/>
        </filter>
    </entity>
</fetch>", queueid.ToString());

string fetchresult = crmservice.Fetch(fetchrequest);
XmlDocument document = new XmlDocument();
document.LoadXml(fetchresult);
Console.Writeline("numero de elementos:" + document.SelectSingleNode("//resultset/result/c").InnerText));
于 2013-03-13T16:08:43.523 回答