JPA CASCADE PERSIST и Spring CrudRepository - PullRequest
0 голосов
/ 19 февраля 2019

(Примечание: отредактировано для добавления кода для воспроизведения поведения)

У меня есть следующие три объекта

@Entity
public class ClassA {
  @Id private UUID id = UUIDGenerator.generate();
  @OneToMany(mappedBy = "classA", cascade = {CascadeType.PERSIST, CascadeType.DETACH,CascadeType.REMOVE}, orphanRemoval = true)
  List<ClassB> classBs= new ArrayList<>();
 //setters and getters
 }

@Entity
public class ClassB {
  @Id private UUID id = UUIDGenerator.generate();

  @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REMOVE},
        orphanRemoval = true, mappedBy = "classB")
  private ClassC classC;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "classA_id")
  private ClassA classA;
  // setters and getters

@Entity
public class ClassC {
  @Id private UUID id = UUIDGenerator.generate();
  @OneToOne //(fetch = FetchType.LAZY)
  @MapsId
  private ClassB classB;
  //setters and getters
}

public interface ClassARepository extends CrudRepository<ClassA, UUID> {}

//Example code to reproduce
ClassC classC_1 = new ClassC();
ClassC classC_2 = new ClassC();
ClassB classB_1 = new ClassB();
ClassB classB_2 = new ClassB();
classC_1.setClassB(classB_1);
classC_2.setClassB(classB_2);
classB_1.setClassC(classC_1);
classB_2.setClassC(classC_2);
ClassA classA = new ClassA();
classB_1.setClassA(classA);
classB_2.setClassA(classA);

classA.getClassBs().add(classB_1);
classA.getClassBs().add(classB_2);

classARepository.save(classA); 

Я использую Spring Boot и CRUD-репозиторий.В первый раз, когда я пытаюсь сохранить сущность типа A, я ожидаю, что из-за аннотации CascadeType.PERSIST будет сохранена вся иерархия классов A, B и C.Однако это не так, и я получаю обратно org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find classB with id ...

Если я изменю тип каскада @OneToMany на CascadeType.ALL, тогда классы A и classB сохраняются, но не classC.Если я изменю все типы каскадов на ВСЕ, тогда все будет сохранено.

Однако я хочу каскадировать операцию сохранения только тогда, когда создается новая сущность, а не при объединении, что, как я полагаю, именно это означает PERSIST.Может ли кто-нибудь объяснить вышеуказанное поведение и как я могу добиться того, чего хочу?

С уважением

1 Ответ

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

Я отвечаю на свой вопрос:

Кажется, проблема в стратегии генерации идентификаторов.В этом случае я генерирую Id перед сохранением в хранилище, и это вызывает проблемы.В частности,

Из того, что я мог видеть SimpleJpaRepository имеет этот код

public <S extends T> S save(S entity) {
    if (this.entityInformation.isNew(entity)) {
        this.em.persist(entity);
        return entity;
    } else {
        return this.em.merge(entity);
    }
}

, где решение о том, является ли объект новым, принимается JpaPersistableEntityInformation здесь:

public boolean isNew(T entity) {
    return entity.isNew();
}

и entity.isNew() определяется следующим образом:

@Transient
public boolean isNew() {
    return null == this.getId();
}

Таким образом, другими словами, стратегия генерации идентификатора фактически влияет на результат каскада.И на самом деле я подтвердил свое предположение, изменив везде идентификаторы на

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

и, вуаля, все работает.

Не идеальная ситуация, но, по крайней мере, я знаю, почему этоэто происходит.Итак, PERSIST в основном применяется только к идентификаторам, сгенерированным в БД?Кажется странным, поэтому, если у кого-то есть предложения о том, как преодолеть эту проблему, сообщите нам.

С уважением

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...