2017-02-01 2 views
1

У меня есть некоторый код следующим образом:«Значение, переданное для ConditionOperator.In пусто» с ConditionExpression использования ConditionOperator.In против пустого массива операнда

QueryExpression qxEmpty = new QueryExpression("systemuser"); 
    object[] guids = (new Guid[] { }).Cast<object>().ToArray(); 
    ConditionExpression c = new ConditionExpression("systemuserid", ConditionOperator.In, guids); 
    qxEmpty.Criteria.AddCondition(c); 
    EntityCollection ecEmpty = service.RetrieveMultiple(qxEmpty); 

Это не будет работать на последнюю строку с FaultException:

The value passed for ConditionOperator.In is empty

Если я инициализирую переменную guids, чтобы содержать один или несколько действительных указаний, существующих в целевом CRM, я получаю ожидаемый результат.

Почему почему RetrieveMultiple генерирует исключение, когда у меня есть условие, которое задает вопрос, является ли значение членом пустого набора? Условие должно оцениваться как false, а RetrieveMultiple должно возвращать пустой EntityCollection, а не исключать исключение, не так ли?

MSDN похоже, что это проблема с перегрузкой метода конструктора ConditionExpression, и чтобы убедиться, что используется соответствующий тип объекта, но насколько я могу судить, я делаю это правильно, передавая массив объектов : https://msdn.microsoft.com/en-us/library/gg334419(v=crm.7).aspx

Я использую версию 7.1.0.1085 в Microsoft.Xrm.Sdk

Edit: Я думаю, я не прошу правильный вопрос. Как передать пустой набор в ConditionExpression для использования с ConditionOperator.In?

Редактировать 2: Хорошо, вот SQL, который я пытаюсь перевести на QueryExpression.

SELECT * 
FROM SystemUser 
WHERE SystemUserId IN 
(
    SELECT SystemUserid 
    FROM SystemUser 
    WHERE X=Y 
) 

Я перевел это примерно следующим образом:

QueryExpression qxEmpty = new QueryExpression("systemuser"); 
object[] guids = getGuids(); // calls a method that executes the subquery 
ConditionExpression c = new ConditionExpression("systemuserid", ConditionOperator.In, guids); 
qxEmpty.Criteria.AddCondition(c); 
EntityCollection ecEmpty = service.RetrieveMultiple(qxEmpty); 

Проблема с вышесказанным он терпит неудачу, когда подзапрос не имеет значения. В SQL это не терпит неудачу, это дает мне пустой набор, который я хочу получить в результате запроса QueryExpression.

Редактировать 3:
Ой, я вдруг понял, почему это глупый вопрос. Поскольку CRM не поддерживает подзапросы, и в любом случае я должен делать это в двух отдельных запросах, я мог бы также не выполнять второй запрос, когда список пуст, потому что я уже знаю результат и поэтому не должен тратить ресурсы. Поэтому, хотя может показаться более элегантным поддерживать передачу пустого массива, на самом деле исключение является хорошим сигналом для меня, чтобы добавить явные проверки кода.

+0

ли вы пытаетесь сделать GUIDs Guid [], не является объектом []? Существует перегрузка объекта [], которую, как я думаю, использует компилятор. См. Https://community.dynamics.com/crm/b/crmdavidjennaway/archive/2011/05/25/unexpected-error-with-conditionoperator-in-and-typed-arrays – Mangist

+0

@Mangist Да, я пробовал что. Если я заменил вторую строку моего выше кода на Guid [] guids = new Guid [] {}; Я получаю то же исключение. – pabrams

ответ

3

Добавление ответа Мэтта, если вы посмотрите на исходный SDK кода, совокупность значений никогда не инициализируется, даже не с пустым DataCollection объекта когда пустые аргументы передаются. Так что это предполагаемое поведение, где in, используя условие IN, ожидает хотя бы один параметр.

SDK Исходный код:

public ConditionExpression(string entityName, string attributeName, ConditionOperator conditionOperator, params object[] values) 
{ 
    this._entityName = entityName; 
    this._attributeName = attributeName; 
    this._conditionOperator = conditionOperator; 
    if (values == null) 
     return; 
    this._values = new DataCollection<object>((IList<object>) values); 
} 

Update # 1: основанный на комментарий SELECT * FROM systemuser where systemuserid IN (select systemuserid from systemuser where 1=2)

Выражения запросов имеют ограничения, не каждый SQL запрос может быть переведен непосредственно. С точки зрения SQL, использование IN определенно имеет некоторые преимущества по сравнению с использованием нескольких условий WHERE, но в данном конкретном случае нет возможности использовать Where - OR.

Update # 2: После того, как все комментарии:

object[] guids = getGuids(); // calls a method that executes the subquery 
if (guids == null || !guids.Any()) return new EntityCollection(new List<Entity>()); 
ConditionExpression c = new ConditionExpression("systemuserid", ConditionOperator.In, guids); 
//rest of the query 
+0

Но я даю ему один параметр: пустой массив - я не передаю null. Я не понимаю, что я должен пропустить. – pabrams

+0

Вы имеете в виду ГДЕ - ИЛИ? Например, вместо использования ConditionOperator.In в одном выражении COnditionExpression для массива я использую ConditionOperator.Equals против каждого значения в массиве (с несколькими выражениями условий), а затем добавляю все эти COnditionExpressions в фильтр OR? – pabrams

+0

Да, несколько условных операторов и группировать их с помощью 'OR', также обновил мой ответ. 1 условный оператор на элемент массива. – dynamicallyCRM

3

Мне исключение неверно, так как запрос не действителен. Ошибка явно говорит вам, что оператор «В» не может иметь пустое значение. Эквивалент в SQL будет

SELECT * FROM systemuser where systemuserid IN() 

Который также будет ошибка синтаксиса:

Incorrect syntax near ')'.

EDIT На основе всех комментариев это звучит, как вы принимаете в динамическом вводе (который может быть null пустой) и хотите, чтобы ваш запрос выполнялся с помощью оператора «В». Лучшим способом, вероятно, будет сбор чеков и не будет выполнять запрос, если он пуст.Если вам все еще нужно выполнить запрос, который вы могли бы сделать что-то вроде:

var input = new Guid[] {}; 
var values = input.Length == 0 ? 
       "<value></value>" : 
       String.Join("", input.Select(x => $"<value>{x}</value>")); 

_orgService.RetrieveMultiple(new FetchExpression(
    [email protected]"<fetch> 
     <entity name='systemuser'> 
      <attribute name='fullname'/> 
      <filter> 
       <condition attribute='systemuserid' operator='in'> 
        {values} 
       </condition> 
      </filter> 
     </entity> 
    </fetch>")); 
+0

Ну, да, это синтаксическая ошибка, но для меня эквивалентный запрос будет похож на SELECT * FROM systemuser, где systemuserid IN (выберите systemuserid из системного пользователя, где 1 = 2). Как это выразить в QueryExpression? Я знаю, что, возможно, я могу взломать вещи, например, проверить, пуст ли массив, и если да, не передавать его или не выполнять выражение, но я надеялся на правильный способ его выполнения. – pabrams

+0

То, что вы описываете, не «хаки» - это правильный способ сделать это. То, что вы описали в своем SQL-запросе, не является эквивалентом того, что вы здесь задаете. Вы не предоставляете суб-запрос, который не возвращает никаких записей, которые явно не содержат никакого ввода для оператора 'IN'. – Nicknow

+0

Так что, возможно, я не задавал правильного вопроса. Как передать пустой набор в ConditionExpression для использования с ConditionOperator.In? – pabrams

Смежные вопросы