Вы должны думать об этом в терминах дерева выражений, и именно так Linq-to-SQL анализирует ваш запрос, чтобы превратить его в SQL.
При проверке дерева оно увидит объект DateTime
, а затем проверит, является ли вызываемый метод одним из поддерживаемых (Add
, AddHours
и т. Д.), Поэтому при непосредственном использовании метода работает отлично.
Когда вы используете какой-либо другой метод расширения, он не может заглянуть внутрь этого метода, чтобы увидеть, что он делает, поскольку информация о теле этого метода отсутствует в дереве выражений, она скрыта в IL. Поэтому не имеет значения, поддерживается ли содержимое метода расширения, потому что Linq-to-SQL не может определить, что это за содержимое.
Смысл создания методов заключается в инкапсуляции и сокрытии информации, что обычно хорошо работает при разработке приложений, но, к сожалению, здесь скрывается информация от Linq-to-SQL, для которой вам нужно иметь возможность просматривать информацию.
В ответ на отредактированный вопрос - как вы это решаете? Если вы хотите сохранить вычисление даты в выражении Linq, единственное, что вы можете сделать для обеспечения эффективности запроса, - это не использовать метод расширения, а просто использовать AddHours(3)
непосредственно для объекта DateTime
.
Это одно из печальных ограничений Linq. Подобно многим вещам, это несколько утечка абстракции, которая, хотя и обеспечивает общий синтаксис для ряда источников, имеет различные ограничения и ограничения в отношении того, какие операции может / будет поддерживать поставщик источника (например, это будет прекрасно работать в Linq-to -Объекты, поскольку для их выполнения не нужно переводить дерево выражений).