Как мне избежать предложения LIKE, используя критерии NHibernate?
Код, который мы используем, прост в этой части поискового запроса:
myCriteria.Add(
Expression.InsensitiveLike("Code", itemCode, MatchMode.Anywhere));
и это прекрасно работает в производственной среде.
Проблема в том, что у одного из наших клиентов есть коды товаров, которые содержат символы%, которым должен соответствовать этот запрос. Результирующий вывод SQL из этого кода похож на:
SELECT ... FROM ItemCodes WHERE ... AND Code LIKE '%ItemWith%Symbol%'
что ясно объясняет, почему они получают странные результаты при поиске предметов.
Есть ли способ включить экранирование с помощью программного Criteria
методы?
Приложение:
Мы используем немного старую версию NHibernate, 2.1.0.4000 (текущая на момент написания статьи - 2.1.2.4853), но я проверил примечания к выпуску, и там не было упоминания об исправлении. Я не нашел ни одной открытой проблемы в их багтрекере.
Мы используем SQL Server, поэтому я могу очень легко избежать специальных символов (%, _, [и ^) в коде, но цель использования NHibernate состояла в том, чтобы сделать наше приложение максимально независимым от базы данных.,
ни Restrictions.InsensitiveLike()
ни HqlQueryUtil.GetLikeExpr()
избежать их входов и удаления MatchMode
Параметр не имеет значения, насколько экранирование идет.
Обновление: я нашел кого-то еще, желающего сделать то же самое (три года назад), и было решено добавить escapeChar
перегружает методы, о которых я упоминал выше (это было "исправлено" в версии 2.0.0.3347). Я добавил комментарий к этому вопросу с просьбой о дальнейшем разрешении.
2 ответа
Единственный способ найти независимость от базы данных - это экранировать каждый символ в строке поиска и вызывать соответствующий конструктор LikeExpression, как и в моем предыдущем ответе. Вы можете сделать это вручную или расширить LikeExpression:
public class LikeExpressionEscaped : LikeExpression
{
private static string EscapeValue(string value)
{
var chars = value.ToCharArray();
var strs = chars.Select(x => x.ToString()).ToArray();
return "\\" + string.Join("\\", strs);
}
public LikeExpressionEscaped(string propertyName, string value, MatchMode matchMode, bool ignoreCase)
: base(propertyName, EscapeValue(value), matchMode, '\\', ignoreCase)
{}
}
Без сомнения, существует более эффективный способ создания экранированной строки (см. Ответы и комментарии к этому вопросу). Использование это:
var exp = new LikeExpressionEscaped("Code", itemCode, MatchMode.Anywhere, true);
myCriteria.Add(exp);
Вы можете создать экземпляр LikeExpression, чтобы выполнить это. В этом примере я экранирую% обратной косой чертой (которая должна быть экранирована):
var itemCode = "ItemWith%Symbol";
itemCode = searchCode.Replace("%", "\\%");
var exp = new LikeExpression("Code", itemCode, MatchMode.Anywhere, '\\', true);
myCriteria.Add(exp);
Я не видел статического метода для возврата выражения LikeExpression с использованием этой перегрузки.
Кстати, если вы используете SQL Server, он по умолчанию не учитывает регистр.