Подтвердить что ты не робот

.NET Entity Framework - использование .Contains() для поиска значения байта в выражении Where

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

Код, который имеет дело с этим:

var ids = parameters.DeliveryID.ToArray(); courses = courses.Where(c => ids.Contains(c.CourseDeliveryID));

В приведенном выше коде:
1. ids - это массив байтов, и я должен убедиться, что он имеет несколько значений перед вызовом Contains().
2. c.CourseDeliveryID - значение байта.

В базе данных я храню CourseDeliveryID как tinyint (SQL Server 2008).

Компиляция просто прекрасна.

Когда я запускаю код, я получаю следующее исключение ArgumentException:
DbExpressionBinding requires an input expression with a collection ResultType.
Parameter name: input

Я нашел документацию для этого исключения: http://technet.microsoft.com/en-us/library/system.data.common.commandtrees.expressionbuilder.dbexpressionbuilder.bindas.aspx

При попытке решить проблему я обнаружил, что если я использую тот же код в shorts, ints или longs, у меня нет проблем.

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

Спасибо заранее!

4b9b3361

Ответ 1

Я смог воспроизвести вашу ошибку в LINQPad и обнаружил, что использование List<byte> вместо byte[] будет работать:

// byte[] ids = new byte[] { 1, 64 };  <== causes ArgumentException
List<byte> ids = new List<byte> { 1, 64};

var c = Courses.Where (co => ids.Contains(co.CourseDeliveryId));

будет генерировать следующие sql и возвращать результаты:

SELECT 
[Extent1].[CourseId] AS [CourseId], 
[Extent1].[CourseName] AS [CourseName], 
[Extent1].[CourseDeliveryId] AS [CourseDeliveryId]
FROM [dbo].[Courses] AS [Extent1]
WHERE [Extent1].[CourseDeliveryId] IN (1,64)

Интересно также, что использование int[] или short[] также будет работать, создавая этот sql:

SELECT 
[Extent1].[CourseId] AS [CourseId], 
[Extent1].[CourseName] AS [CourseName], 
[Extent1].[CourseDeliveryId] AS [CourseDeliveryId]
FROM [dbo].[Courses] AS [Extent1]
WHERE (1 =  CAST( [Extent1].[CourseDeliveryId] AS int)) OR (64 =  CAST( [Extent1].[CourseDeliveryId] AS int))

но с помощью byte[] вызывает исключение. Я могу только догадываться, что поставщик SQL Server EF пытается обработать byte[] каким-то особым образом, в результате чего возникает это исключение.

Ответ 2

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

IEnumerable<byte> ids = parameters.DeliveryID.ToArray();
courses = courses.Where(c => ids.Contains(c.CourseDeliveryID));

(В этом конкретном случае вы можете просто использовать ToList() вместо ToArray(), но в общем случае, если вы получите массив байтов и не хотите перестраивать его как список, который это сделает)