Проблема
Я разрабатываю приложение с пружинной загрузкой, которое должно считывать данные из базы данных oracle.
Сама база данных находится вне моего контроля, и я не могу изменить ее структуру.
Я использую spring-data-jpa в сочетании с hibernate для взаимодействия с базой данных.
У меня есть следующая сущность:
@Entity
@Table(name = "mytable")
public class MyEntity {
@Id
@Column
private String entityId;
// This column might have a value like "abc,xyz,a1b" in the db
@Column
private String associatedIds;
}
Столбец associatedIds
содержит значения, разделенные запятыми ( например. abc,xyz,a1b
).
Пользователи моего приложения имеют разрешение только на чтение строк, по крайней мере, 1 associatedId
, к которым они имеют доступ. Идентификаторы, к которым они имеют доступ, представлены как List<String> allowedIds
.
Чтобы пользователи могли получать только те данные, которые им разрешены, мне нужно ограничить свои запросы. У меня возникают проблемы при создании запроса, отвечающего моим требованиям.
Если бы у пользователей был доступ только к одному идентификатору, я мог бы просто использовать следующий запрос, используя простой оператор LIKE
:
@Query(value = "SELECT e FROM MyEntity e WHERE e.associatedIds LIKE '%:allowedId%'")
Page<MyEntity> findAllByAllowedId(@Param("allowedId") String allowedId, Pageable pageable);
То запроса недостаточно для моего варианта использования, поскольку пользователи имеют доступ к нескольким идентификаторам.
Я придумал несколько способов решения этой проблемы, но не смог полностью реализовать ни один из них.
Подход 1: "IN LIKE"
Первым подходом был бы такой запрос:
@Query(value = "SELECT e FROM MyEntity e WHERE e.associatedIds IN (LIKE '%:allowedIds%')")
Page<MyEntity> findAllByAllowedIds(@Param("allowedIds") List<String> allowedIds, Pageable pageable);
Это не работает, потому что, насколько я знаю, там нет запроса, объединяющего IN
и LIKE
.
Подход 2: «AttributeConverter»
Следующее, что я попробовал, было преобразовать разделенную запятыми строку в List<String>
, используя следующий преобразователь:
@Converter
public class StringArrayToStringConverter implements AttributeConverter<List<String>, String> {
@Override
public String convertToDatabaseColumn(List<String> strings) {
return strings == null ? null : StringUtils.join(strings, ',');
}
@Override
public List<String> convertToEntityAttribute(String s) {
if(StringUtils.isBlank(s)) {
return Collections.emptyList();
}
return Arrays.asList(s.split(","));
}
}
This преобразование работает, но не позволяет мне строить запросы, как если бы столбец был списком, потому что база данных остается неизменной.
Подход 3: "@Formula"
Другим возможным решением может быть аннотация @Formula в hibernate. Там может быть способ создать виртуальный столбец, который можно искать в соответствии с моими требованиями. Я не имею ни малейшего понятия, с чего начать, поскольку я никогда раньше не использовал эту аннотацию и не совсем понимаю, как типы списков работают в oracle. Еще одна вещь, которую стоит рассмотреть, - можете ли вы на самом деле выполнять hql-запросы к столбцам формулы.
Подход 4: «Несколько OR»
Последнее возможное решение, которое я мог бы найти, включало бы добавление отдельного предложения where для каждого разрешенного идентификатора, в конечном итоге это могло бы выглядеть так:
SELECT e FROM MyEntity e WHERE e.allowedIds LIKE'%allowedIds.get(0)%' OR e.allowedIds LIKE'%allowedIds.get(1)%' etc..
При таком подходе я также не знаю, как мне это реализовать в spring-data-jpa.
Я был бы очень признателен за некоторые рекомендации о том, как реализовать эти решения или предложения, о которых я не думал.