Критерии Jpa, равные Predicate для свойства таблицы String (с символом newLine '\ n') не работают, когда в MySQL Workbench это работает - PullRequest
0 голосов
/ 12 февраля 2019

, как следует из названия, у меня возникла проблема при попытке использовать JPA Criteria с Spring Boot для конкретного случая.

Обычно все работает, но пытается найти сохраненные данные с помощью свойства String, имеющегоnewLine character встроенный (\n), похоже, не работает.

Я могу Get данные, редактировать их, сохранять их через мой интерфейс, создавать новые с несколькими строками и т. Д., Нопытаясь найти их, когда, например, столбец равен 'hello\nworld', он не будет работать, хотя выполнение этого запроса в MySQL Workbench возвращает нужные данные:

select * from kerkinidb.ct_thhlastika_press_threats where description_en = 'hello\nworld';

Чтобы уточнитья выполняю поиск, ожидая в Get запроса аргумента search, который имеет все свойства, отфильтрованные пользователем.Я сопоставляю его с Regex (который также имеет внутри Java 8.0 new Regex \\\\R для сопоставления с multilines (и это работает)), затем я даю Service layer Search Criteria, который я сопоставил, который затем переходит кJpa Criteria Repository для их анализа и generating the Predicates (снова совпадающие с Regex and \\\\R для создания окончательного Predicate with OR and ANDs для фильтрации), затем triggering the query, затем another query called count для реализации Pagination и, наконец, mapping дляпользовательский объект и его возвращение.

Я отлаживал каждый шаг, и последний предикат генерирует нужный мне запрос, но БД не возвращает ожидаемые данные.Поэтому я действительно запутался, поскольку, как я уже сказал, запрос работает в MySQL Workbench.

. Это пример ведения журнала (я включил ведение журнала Spring Boot для MySQL logs), генерируемого при запуске запроса.(в этом случае сохраненные данные, которые у меня есть в моих Table ct_thhlastika_press_threats в column description_en, равны a\ns\ndd, поэтому я ищу их, как вы можете видеть вместо примера, который я говорил ранее hello\nworld:


2019-02-12 16:01:01.929 DEBUG 18368 --- [nio-8080-exec-2] org.hibernate.SQL                        : select ctthhlasti0_.id as col_0_0_, ctthhlasti0_.act_code as col_1_0_, ctthhlasti0_.description_en as col_2_0_, ctthhlasti0_.remarks as col_3_0_ from ct_thhlastika_press_threats ctthhlasti0_ where 1=1 and ctthhlasti0_.description_en=? order by ctthhlasti0_.id asc limit ?
2019-02-12 16:01:01.933 TRACE 18368 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [a\ns\ndd]
2019-02-12 16:01:01.944 DEBUG 18368 --- [nio-8080-exec-2] org.hibernate.SQL                        : select count(ctthhlasti0_.id) as col_0_0_ from ct_thhlastika_press_threats ctthhlasti0_ where 1=1 and ctthhlasti0_.description_en=?
2019-02-12 16:01:01.944 TRACE 18368 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [a\ns\ndd]
2019-02-12 16:01:01.946 TRACE 18368 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([col_0_0_] : [BIGINT]) - [0]

Для тех, кто хочет заглянуть дальше в код, вы можете найти его Github repo . Проект предназначен для моей университетской диссертации. Я сделал комментарии для добавления в Regexes (оба из них) для контроллера ctThhlastikaPressThreats иРепозиторий. Необходимо создать базу данных (стандартную и вторичную для тестирования) (можно создать, изменив auto-dll в application.properties).




Обновление

Я пытался использовать System.lineSeparator() (как предложено @Hermann Steidel в ответе ниже), заменяя текст newLine \n. Но даже влоги мы можемТеперь ясно видим, что значение для Predicate equals имеет разделение строк, оно все еще не возвращает данные из БД.

Дальше Объяснение моей реализации

ПравильноЗапрос на динамический поиск выглядит следующим образом:

http://localhost:8080/v1/ctThhlastikaPressThreats/search?search=descriptionEn~hello\nworld;@&size=10&page=0&sort=Asc

Как вы можете видеть, я использую переменную пути с именем search (которая имеет все свойства фильтрации, запрошенные у пользователя), а также еще 3 для size, page и sort.

Для переменной search я использую 3 различных символа для реализации ИЛИ и И Предикаты И для окончательного запроса.Это ~, который должен знать, что свойство, прежде чем оно должно использовать равный предикат, ;, которое должно иметь возможность иметь несколько значений для каждого свойства, запрошенного пользователем, и, наконец, @, которое вызываетконец фильтрации этого свойства.

Эти 3 символа находятся в Regexed в двух местах.В Controller и в SearchRepository из (например, поскольку мы специально начали с этого -> CtThhlastasikaPressThreats)

Наконец, в SearchRepository вы можете видеть, что я запускаю 2 запроса, одинэто получение отфильтрованных данных из базы данных, а другое - получение количества данных для целей нумерации страниц, а также в конечном сопоставлении с пользовательским DTO.

Шаги для воспроизведения:

После генерации БД измените на 2 регулярных выражения CtThhlastikaPressThreats.Для Controller будет (\w+?)(~|<|>)([(!-/.\\\\R 0-9\p{L});]+)?@ и для SearchRepository будет ([(!-/.\\\\R 0-9\p{L})]+).

Затем вы можете использовать приведенный выше пример запроса, когда в БД сохранены для конкретной таблицы и для столбца descriptionEn, например, со значением hello\nworld или любым другим значением, которое вы указали (также измените его наrequest).

Последнее, что я пробовал, но не было решения:

Поместите в хранилище CtThhlastikaPressThreatsSearch в методе search (это после строки 61) вышеthe:

predicate = builder.equal(root.get(param.getKey()), match.toString());

Сделать так:

match = match.toString().replace("\\n", System.lineSeparator()); predicate = builder.equal(root.get(param.getKey()), match.toString());

Это в основном изменит значение с hellow\nworld на hello\r\nworld так что я думаю, что это все еще не желаемое решение.Думая, что в БД он хранится как \n для lineSeparators.

Теперь в журналах вы можете увидеть, что при повторном запуске запроса на получение значение VARCHAR descriptionEn действительно теперь с разделением строквместо текста \n (который все еще должен распознаваться MySQL).

Заключительные мысли

Я верю, поскольку даже это

select * from kerkinidb.ct_thhlastika_press_threats where description_en = 'hello\nworld';

работает в MySQL Workbench, что что-то среднее может испортить запрос при попытке также включить newLine char или lineSeparators.




Еслиесть какие-то идеи о том, почему это не работает, как задумано, пожалуйста, поделитесь, чтобы попробовать это.

Спасибо за ваше время

1 Ответ

0 голосов
/ 14 февраля 2019

Я получил его на работу.Возможно, это не тот ответ, который вы хотели, но, если вы замените свои входящие "\ n" на системный разделитель строк, он получит то, что вы хотите.

 search = search.replace("\\n", System.getProperty("line.separator"));
 try {
    return ctThhlastikaPressThreatsService.searchCtThhlastikaPressThreats(producedSearchCriterias(search), size, page, sort);

Если вы посмотрите на регистрацию значений параметров,вы увидите, что параметр теперь

extracted value ([col_2_0_] : [VARCHAR]) - [hello
world]

вместо

extracted value ([col_2_0_] : [VARCHAR]) - [hello\nworld]

Как я и подозревал, где-то в конвейере поиска он выходит за пределы \ n.Я не предлагаю вам делать то, что я предлагаю прямо на контроллере, я просто хотел показать вам, что это то, что должно произойти (где-то), чтобы он работал.

...