Как мне избежать предложения 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, он по умолчанию не учитывает регистр.

Другие вопросы по тегам