Я столкнулся со сценарием, в котором LINQ to SQL действует очень странно. Я хотел бы знать, если я делаю что-то не так. Но я думаю, что есть реальная возможность, что это ошибка.
Код, вставленный ниже, не является моим настоящим кодом. Это упрощенная версия, которую я создал для этого поста, используя базу данных Northwind.
Немного предыстории: у меня есть метод, который принимает IQueryable
из Product
и "объект фильтра" (который я опишу через минуту). Он должен запустить некоторые методы расширения «Где» на IQueryable
на основе «объекта фильтра», а затем вернуть IQueryable
.
Так называемый «объект фильтра» - это System.Collections.Generic.List
анонимного типа этой структуры: { column = fieldEnum, id = int }
FieldEnum - это перечисление различных столбцов таблицы Products
, которые я, возможно, хотел бы использовать для фильтрации.
Вместо дальнейшего объяснения того, как работает мой код, будет проще, если вы просто посмотрите на него. Это просто следовать.
enum filterType { supplier = 1, category }
public IQueryable<Product> getIQueryableProducts()
{
NorthwindDataClassesDataContext db = new NorthwindDataClassesDataContext();
IQueryable<Product> query = db.Products.AsQueryable();
//this section is just for the example. It creates a Generic List of an Anonymous Type
//with two objects. In real life I get the same kind of collection, but it isn't hard coded like here
var filter1 = new { column = filterType.supplier, id = 7 };
var filter2 = new { column = filterType.category, id = 3 };
var filterList = (new[] { filter1 }).ToList();
filterList.Add(filter2);
foreach(var oFilter in filterList)
{
switch (oFilter.column)
{
case filterType.supplier:
query = query.Where(p => p.SupplierID == oFilter.id);
break;
case filterType.category:
query = query.Where(p => p.CategoryID == oFilter.id);
break;
default:
break;
}
}
return query;
}
Итак, вот пример. Допустим, список содержит два элемента этого анонимного типа, { column = fieldEnum.Supplier, id = 7 }
и { column = fieldEnum.Category, id = 3}
.
После выполнения приведенного выше кода базовый SQL-запрос объекта IQueryable
должен содержать:
WHERE SupplierID = 7 AND CategoryID = 3
Но на самом деле, после запуска кода SQL, который будет выполнен, будет
WHERE SupplierID = 3 AND CategoryID = 3
Я попытался определить query
как свойство и установить точку останова на сеттере, думая, что смогу понять, что его меняет, когда этого не должно быть. Но якобы все было хорошо. Поэтому вместо этого я просто проверял базовый SQL после каждой команды. Я понял, что первый Where
работает нормально, а query
остается в порядке (имеется в виду SupplierID = 7
) до тех пор, пока цикл foreach
не запустится во второй раз. Сразу после того, как oFilter
становится вторым элементом анонимного типа, а не первым, SQL-запрос «запрос» меняется на Supplier = 3
. Таким образом, то, что должно происходить здесь скрытно, заключается в том, что вместо того, чтобы просто помнить, что Supplier
должно равняться 7, LINQ to SQL помнит, что поставщик должен равняться oFilter.id
. Но oFilter
- это имя отдельного элемента цикла foreach
, и после итерации оно означает что-то другое.