CRM FetchXml, как я могу динамически добавить фильтр быстрого поиска, который будет соответствовать имени связанной сущности?

У меня есть веб-страница вне CRM, которая позволяет пользователям выполнять поиск в CRM. Мне нужно реализовать фильтрацию результатов поиска с помощью быстрого поиска, как в обычном пользовательском интерфейсе CRM.

Я получаю FetchXML для выбранной сущности / представления, затем получаю FetchXML для представления быстрого поиска выбранной сущности, извлекаю узел фильтра, где isquickfindfields = 1, заменяю {0} тем, что они ввели в поле поиска, вставляю измененный узел в FetchXML выбранного представления и выполните его.

Проблема, с которой я сталкиваюсь, заключается в том, что некоторые из фильтров быстрого поиска относятся к полю идентификатора связанной сущности, но соответствие должно совпадать с атрибутом первичного имени этой сущности.

Например, вот быстрый поиск сущности аккаунта:

<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>

And when I plug in the search text and execute the view, I get this error from 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, мой вопрос заключается в том, как мне динамически применять фильтрацию быстрого поиска к запросам / представлениям, которые будут правильно фильтровать по атрибуту основного имени связанной сущности?


[Изменить для пояснения]

Быстрый поиск (или Быстрый поиск) - это один из типов представления в CRM. Он определяет, какие атрибуты ищутся, когда пользователь вводит текст в поле быстрого поиска или при фильтрации поиска. Все объекты имеют представление быстрого поиска, а объект может иметь только одно.

Требование соответствия имени связанной сущности исходит из представления быстрого поиска. Не все из них включают фильтр для ссылки на сущность, но когда он есть, мне нужно сопоставить имя, а не guid. Поскольку обычный пользовательский интерфейс CRM правильно применяет строку поиска к имени связанной сущности, даже несмотря на то, что FetchXML представления быстрого поиска имеет фильтр по идентификатору, я думал, что 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 (добавление / удаление объектов, добавление / удаление / обновление представлений) потребуют обновления кода для соответствия.


person Jeff Shepler    schedule 13.03.2013    source источник


Ответы (3)


Я не знаю, как CRM сходит с рук с предположительным использованием строки для поиска по руководству, но я подозреваю, что он выполняет некоторую предварительную обработку или некоторые внутренние вещи, которые могут быть вам недоступны. (Я полагаю, если вы действительно хотите знать, вы можете попробовать декомпилировать .dll CRM, но это может занять некоторое время).

Поэтому в качестве альтернативы я бы предложил этап обработки, на котором вы дополнительно манипулируете FetchXml, если вы сделаете это с помощью службы метаданных, вы сможете обойтись без какого-либо жесткого кодирования.

Итак, взяв в качестве примера выборку учетной записи, я считаю, что вам нужно отредактировать xml, чтобы к нему был добавлен атрибут id name, например primarycontactidname. Это имя столбца базы данных в FilteredView, и я считаю, что он доступен из FetchXml. (Если это не сработает, добавьте link-entity с фильтром для имени и удалите существующее условие).

Итак, вы знаете, когда добавлять name, я бы посоветовал:

  1. Получить критерии поиска в режиме быстрого поиска.
  2. Для каждого условия используйте службу метаданных для поиска CRM
  3. Если тип поля - EntityReference, обновите поиск в режиме быстрого поиска с соответствующим условием.
person James Wood    schedule 13.03.2013
comment
Я надеялся, что мне не придется делать что-то подобное. Это просто плохо. Это похоже на добавление дополнительных накладных расходов, чем необходимо, и ухудшение отзывчивости приложения. Возникает вопрос, почему они сделали это с самого начала - они должны были бы сделать то же самое в своем пользовательском интерфейсе, так зачем вообще добавлять фильтр идентификаторов? Наиболее распространенным вариантом использования будет сопоставление имен, а не сопоставление руководств. Это заставляет меня думать, что есть что-то еще. - person Jeff Shepler; 14.03.2013
comment
Что ж, если вы узнаете, что это за что-то еще, пожалуйста, вернитесь и скажите мне: D - person James Wood; 14.03.2013
comment
Смена ..id на ..idname - вот как я закончил. Кроме того, добавление объекта ссылки с фильтром выполняется с помощью операции AND к другим фильтрам, и я не вижу никакого способа изменить это (атрибут type применяется только к дочерним условиям). Я не могу полностью выполнить то, что от меня просят, но это лучшее, что я могу найти. Спасибо. - person Jeff Shepler; 23.03.2013
comment
Кстати, я имел в виду, что я надеялся, что мне не придется предварительно обрабатывать fetchxml, перебирать атрибуты, чтобы узнать, являются ли они ссылками на сущности, и соответственно изменять fetchxml, все для реализации функций, которые (я думаю) уже должны работать так. - person Jeff Shepler; 23.03.2013

Я проголосовал за ответ Джеймса, потому что думаю, что это правильный ответ на ваш вопрос. Однако, возможно, лучшим решением в целом было бы создание специального системного представления для каждой сущности, которую вы хотите сделать доступной для поиска на вашей веб-странице (страницах). Используйте соглашение об именах, чтобы ваша веб-страница знала, в каком системном представлении искать. В системном представлении укажите {0} в полях критериев, а затем замените его в своем коде, как обычно. Таким образом, вы можете создать любой сложный FetchXML без дополнительных затрат на запросы к службе метаданных. Для получения бонусных баллов отключите это новое представление системы, чтобы оно не отображалось в пользовательском интерфейсе CRM.

-Дополнения после ваших комментариев ниже:

Быстрый поиск на самом деле не «фильтрует просмотры / просмотры». Когда вы вводите запрос в поле «Быстрый поиск» в пользовательском интерфейсе CRM, он не фильтрует текущее представление - результаты отображаются в представлении «Быстрый поиск» (см. Раскрывающееся меню «Просмотр»). Как вы видели, в этом представлении используется специальный FetchXML - атрибут isquickfindfields. Этот атрибут должен быть флагом пользовательского интерфейса CRM для предварительной обработки этого FetchXML и обновления узла, чтобы исправить FetchXML для этих полей отношений перед отправкой запроса.

Если вы намерены отобразить все системные представления в этом альтернативном пользовательском интерфейсе, но разрешить их фильтровать с помощью чего-то похожего на поле поиска быстрого поиска, то вы говорите о чем-то, что совсем не похоже на пользовательский интерфейс CRM. :)

Если вы говорите об использовании одних и тех же параметров представления быстрого поиска в этом альтернативном пользовательском интерфейсе, то я все же рекомендую создать единое скрытое представление системы в CRM, которое имитирует представление быстрого поиска. FetchXML, стоящий за этим представлением, будет «нормальным», и вы сможете вставить текст для поиска без необходимости вызова службы метаданных.

person Josh Painter    schedule 17.03.2013
comment
Я действительно не понимаю, чем это отличается от строк FetchXML с жестким кодированием в приложении. Мне нужно было бы иметь специальное представление для каждого нормального представления (чтобы их можно было фильтровать), и мне пришлось бы поддерживать эти специальные представления - всякий раз, когда представление создается / обновляется / удаляется, специальное представление должно быть создано / обновлено / удалено, чтобы соответствовать. - person Jeff Shepler; 19.03.2013
comment
Кроме того, они хотят, чтобы приложение работало так же, как обычный пользовательский интерфейс CRM. При фильтрации запросов / просмотров используется режим быстрого поиска. - person Jeff Shepler; 19.03.2013
comment
Мои ответы на ваши комментарии были слишком длинными, поэтому я добавил их выше в качестве редактирования. - person Josh Painter; 20.03.2013
comment
Ты прав! Представление быстрого поиска не фильтрует выбранное представление и даже не используется при фильтрации результатов поиска. Также было обнаружено, что вы не можете ИЛИ связать фильтры сущностей с другими фильтрами (например, перечислить встречи с темой типа «% xxx%» ИЛИ link-entity-lead.companyname с типом «% xxx%»). - person Jeff Shepler; 23.03.2013

Надеюсь, я понял ваш вопрос. primarycontactid - это не имя, это гид, который представляет собой запись, в данном случае контакт. Если ваши пользователи не знают 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>

Выполнить FetchXML в C # динамически:

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));
person Pedro Azevedo    schedule 13.03.2013
comment
Это нормально для этого конкретного примера, но мне нужно делать это динамически. Это означает, что я не хочу жестко кодировать все возможные фильтры в веб-приложении, плюс необходимость изменять код каждый раз при добавлении или изменении представления. - person Jeff Shepler; 13.03.2013
comment
извините, я не понимаю этого, я обновляю, как я это делаю, это еще один пример, адаптированный к вашему случаю - person Pedro Azevedo; 13.03.2013
comment
Ваш второй пример все еще имеет жестко запрограммированный FetchXML и явно ожидает Guid. Мой вопрос не касался ошибки или соответствия руководств. - person Jeff Shepler; 13.03.2013
comment
Я не понимаю вашего вопроса. Второй пример - динамический, потому что вы можете передать значение любому фильтру, верно? В этом примере я передаю гид, но вы можете передать строку. - person Pedro Azevedo; 13.03.2013
comment
Я имел в виду, что мне не нужен набор заранее определенных жестко заданных строк fetchxml в моем приложении. Он должен работать с тем, что определено в CRM во время выполнения кода, и не иметь специального кода для обработки каждого типа сущности. Я обновил свой вопрос (надеюсь) некоторыми пояснениями. - person Jeff Shepler; 14.03.2013