Мне интересно, возможно ли с JPA (Hibernate) сохранять и обновлять объекты косвенно через владельца ассоциации.Каскадирование в JPA. Персистировать и объединять сущности через владельца ассоциации
В моем проекте есть два источника данных. Я пытаюсь найти способ обмена некоторыми объектами между базами данных. Для этого мне просто нужно отсканировать его дважды с каждым из моих застройщиков-менеджеров. Согласно моей идее, в обеих базах данных можно использовать объект Employee
. Для этого мне просто нужно создать объект Phone
во втором источнике данных, и все его поля будут перенесены через Hibernate в мою вторую базу данных.
Вот пример кода (я использовал lombok и удален импорт, чтобы упростить его)
@Entity
@Table(uniqueConstraints = {
@UniqueConstraint(columnNames = {"name"})})
@lombok.NoArgsConstructor(access = PROTECTED)
@lombok.AllArgsConstructor
@lombok.Data
public class Employee {
@Id
private Long id;
private String name;
}
@Entity
@lombok.Data
@lombok.NoArgsConstructor(access = PROTECTED)
public class Phone {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(cascade = {PERSIST, MERGE, REFRESH})
@JoinColumn(name = "em_id")
private Employee employee;
private String number;
public Phone(Employee employee, String number) {
this.employee = employee;
this.number = number;
}
}
Я хотел бы использовать Spring Data JPA PhoneRepository настроен для работы с моим вторым источником данных
public interface PhoneRepository extends JpaRepository<Phone, Long> {}
И EmployeeRepository, как я думаю, можно использовать только один раз для настройки с помощью первого источника данных. Все отношения во второй базе данных могут создаваться автоматически с помощью Spring/Hibernate. По крайней мере, мне хотелось бы этого. В моих тестах ниже он сконфигурирован с моим вторым источником данных только для иллюстративных целей.
public interface EmployeeRepository extends JpaRepository<Employee, Long> {}
Вот некоторые тесты
@Autowired
EmployeeRepository employeeRepository;
@Autowired
PhoneRepository phoneRepository;
/**
* Passes successfully.
*/
@Test
public void shouldPersitPhonesCascaded() {
phoneRepository.save(new Phone(new Employee(1L, "John Snow"), "1101"));
phoneRepository.save(new Phone(new Employee(2L, "Hans Schnee"), "1103"));
}
/**
* Causes <blockquote><pre>
* org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PRIMARY KEY ON PUBLIC.EMPLOYEE(ID)"; SQL statement:
* insert into employee (name, id) values (?, ?) [23505-190]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
* at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
* ...
* </pre></blockquote>
*/
@Test
public void shouldMergePhonesCascaded() {
Employee employee = new Employee(1L, "John Snow");
phoneRepository.save(new Phone(employee, "1101"));
phoneRepository.save(new Phone(employee, "1102"));
}
/**
* Works with changed Phone entity's field.
* <blockquote><pre>
* {@literal @}ManyToOne
* {@literal @}JoinColumn(name = "em_id")
* private Employee employee;
* </pre></blockquote>
*/
@Test
public void shouldAllowManualMerging() {
Employee employee = new Employee(1L, "John Snow");
employeeRepository.save(employee);
phoneRepository.save(new Phone(employee, "1101"));
phoneRepository.save(new Phone(employee, "1102"));
}
В идеале я хотел бы взять объект (Employee
) из моего первого источника данных, поместите его в оберточную сущности (Phone
) от моего второго источника данных и обновления вторая база данных без нарушений.