У меня есть доменный объект в Spring, который я сохраняю, используя метод JpaRepository.save и используя генератор последовательностей из Postgres для автоматического создания идентификатора.
@SequenceGenerator(initialValue = 1, name = "device_metric_gen", sequenceName = "device_metric_seq")
public class DeviceMetric extends BaseTimeModel {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "device_metric_gen")
@Column(nullable = false, updatable = false)
private Long id;
///// extra fields
В моем сценарии использования требуется выполнить upsert
вместо обычной save
операции (которая, как я знаю, будет обновляться при наличии идентификатора). Я хочу обновить существующую строку, если присутствует комбинация из трех столбцов (предположим, составной уникальный) или создать новую строку. Это что-то похожее на this :
INSERT INTO customers (name, email)
VALUES
(
'Microsoft',
'hotline@microsoft.com'
)
ON CONFLICT (name)
DO
UPDATE
SET email = EXCLUDED.email || ';' || customers.email;
Один из способов достижения того же в Spring-данных, о которых я могу подумать:
- Написатьпользовательская операция сохранения в слое обслуживания, которая
- выполняет получение для трех столбцов и, если имеется строка,
- Установите тот же идентификатор в текущем объекте и выполните repository.save
- Если строки нет, создайте обычный репозиторий.save
Проблема с вышеприведенным подходом заключается в том, что каждый insert
теперь делает select
, а затем save
, что делает два вызова базы данных. в то время как то же самое может быть достигнуто с помощью функции postgres insert on conflict
всего с одним вызовом базы данных. Любые указатели о том, как реализовать это в Spring Data?
Один из способов - написать собственный запрос insert into values (all fields here)
. У рассматриваемого объекта около 25 полей, поэтому я ищу другой лучший способ добиться того же.