Linq to NHibernate и Dynamic LINQ - кеширование запросов не работает
У меня проблема с кешем второго уровня NHibernate. Когда я использую запрос:
var items1 = Session.Query<Row>()
.Cacheable();
.Fetch(x => x.Field)
.OrderBy(x => x.Field.Value)
.ToList();
Все хорошо - запрос кешируется. Но когда я хочу использовать Dynamic Linq ( ссылка):
var items2 = Session.Query<Row>()
.Cacheable();
.Fetch(x => x.Field)
.OrderBy("Field.Value")
.ToList();
Запрос не кэшируется. Интересно то, что когда я удаляю строку кода:
.Fetch(x => x.Field)
кеширование снова работает Таким образом, проблема заключается в совместном использовании методов Fetch и динамического linq OrderBy.
РЕДАКТИРОВАТЬ:
Когда я пытаюсь выполнить отладку кода NH (класс QueryKey), отладчик говорит мне, что эти два запроса не имеют один и тот же ResultTransformer (и глубже: частный экземпляр listTransformation).
Есть идеи?
Крис
1 ответ
Хорошо, я знаю, в чем причина.
Динамический Linq не использует имена параметров в выражениях Linq. Например, если я хочу отсортировать с помощью лямбда-состояний, я пишу:
query.OrderBy(item => item.Name)
Выше мы видим item
имя лямбда-параметра.
Когда я использую Dynamic LINQ:
query.OrderBy("Name")
в результате Queryable лямбда-параметр в методе OrderBy не имеет имени (например, item
написано выше). Мы можем проиллюстрировать результат следующим образом:
query.OrderBy( => .Name)
И теперь, когда NHibernate декодирует это выражение Queryable и находит там параметр выражения, который не имеет имени, NH дает ему случайное имя, используя класс GUID. Таким образом, каждое упорядочение с использованием динамического linq создает выражение Queryable Expression, которое имеет непостоянный параметр лямбда Именно поэтому NHibernate считает, что: query.OrderBy("Name")
а также query.OrderBy("Name")
не одинаковы - у них есть другие параметры лямда, генерируемые каждый раз с нуля.
РЕШЕНИЕ
Если вы хотите это исправить, вы должны изменить библиотеку Dynamic Linq.
В методе
ExpressionParser.ProcessParameters
изменить строку:if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name))
чтобы:
if (parameters.Length == 1 && (parameters[0].Name == "it" || String.IsNullOrEmpty(parameters[0].Name)))
В методе
DynamicQueryable.OrderBy
изменить строку:Expression.Parameter(source.ElementType, "")
чтобы:
Expression.Parameter(source.ElementType, "it")
Сейчас, query.OrderBy("Name")
будет производить query.OrderBy(it => it.Name)
,
Ура!