#postgresql #hibernate #spring-data-jpa #jpql
#postgresql #переход в спящий режим #spring-data-jpa #jpql
Вопрос:
В ненормализованной базе данных PostgreSQL: две таблицы «Документ» и «Запись»
Документ содержит идентификатор и столбец recodeIds, разделенный запятыми
--------------------------------------
| id (VARCHAR) | recordIds (VARCHAR) |
--------------------------------------
| 1 | 3,1 |
| 2 | 2 |
--------------------------------------
Запись имеет идентификатор и имя
---------------------------------
| id (VARCHAR) | name (VARCHAR) |
---------------------------------
| 1 | X |
| 2 | Y |
| 3 | Z |
---------------------------------
DocumentModel с @Convert
@Entity
@Table(name = "Document")
public class DocumentModel {
@Id
@Column(name = "id")
private String id;
@Column(name = "recodeIds")
@Convert(converter = RecordsConverter.class)
private Set<String> records;
}
RecordsConverter
public class RecordsConverter implements AttributeConverter<Set<String>, String> {
@Override
public String convertToDatabaseColumn(Set<String> recordTypes) {
return String.join(",", recordTypes);
}
@Override
public Set<String> convertToEntityAttribute(String recordTypes) {
return Arrays.stream(recordTypes.split(",")).collect(Collectors.toSet());
}
}
JPQL Теперь я пытаюсь использовать записи в @Query
@Query("SELECT D.id, R.name)"
" FROM DocumentModel D"
" JOIN RecordModel R"
" ON R.id IN D.records"
" WHERE D.id = :docId"
Это работает только в том случае, если идентификаторы записей имеют одно значение (пример: docId = 2)
Это не работает, если идентификаторы записей имеют несколько значений (пример: docId = 1), даже если:
- Вложенный ВЫБОР не работает
- В предложении с и без () не работает
- ЧЛЕН предложения не работает
- Полученный собственный SQL напрямую не работает
- @Формула не работает
И, похоже, проблема в том, что записи должны заключаться в одинарные кавычки, разделенные запятыми, а не только разделяться запятыми, поскольку они являются строками. (В этом случае работает собственный SQL-запрос)
Вопрос: Как заставить это работать, используя JPQL (не собственный запрос) без изменения RecordsConverter и, надеюсь, без спецификаций JPA?
Комментарии:
1. Лучший способ решить эту проблему — нормализовать вашу модель данных. Хранение значений, разделенных запятыми, в одном столбце с самого начала является огромной ошибкой
2. Вы правы, но клиент отказался :/
3. @AhmedGhoneim Работает ли это в sql-запросе, аналогичном вашему JPQL?
4. Нет. Он работает только со значениями, заключенными в одинарные кавычки, разделенные запятыми
5. Вы могли бы создать представление, представляющее нормализованную версию
document
таблицы. Затем вы используете обычное объединение, чтобы объединить его сRecord
таблицей
Ответ №1:
Похоже, на меня повлияла ошибка гибернации
В качестве обходного пути используйте обертки коллекции:
@Data
@Builder
public class MyCollection implements Serializable {
private final Set<String> collection;
}
и измените свой конвертер атрибутов:
public class MyConverter implements AttributeConverter<MyCollection, String> {
@Override
public String convertToDatabaseColumn(MyCollection myCollection) {
return String.join(",", myCollection.getCollection());
}
@Override
public MyCollection convertToEntityAttribute(String myCollection) {
return MyCollection.builder()
.collection(Arrays.stream(myCollection.split(",")).collect(Collectors.toSet()))
.build();
}
}
и вы моделируете:
@Entity
@Table(name = "MY_MODEL")
public class MyModel {
@Column(name = "MY_COLLECTION")
@Convert(converter = MyConverter.class)
private MyCollection myCollection;
}
Это сработало для меня.