Serhii
Serhii

Reputation: 7563

Spring data JPA. Cascade update works for special cases only

Most important structural description:

In my application is used Spring data JPA. I have a model part in my application:

@Entity
public class Event implements Identifiable {
  // ...
  @OneToMany(cascade = CascadeType.ALL, mappedBy = "event", orphanRemoval = true)
  @OrderColumn(name = "order_index")
  private List<Attendee> attendees = new ArrayList<>();
  // ...
}

@Entity
public class Attendee implements Identifiable {
  // ...
  @ManyToOne
  @JoinColumn(columnDefinition = "event_id")
  private Event event;
  // ...
}

It should be clear for all who knows JPA.

I've implemented test to save an event, as result dependent attendees collection saves also (hibernate magic used because of correspond relation settings shown in very beginning.)

eventRepository.save(event);

provides save|update event and replace all old nested attendees with new ones.

Problem description:

Some times I need use additional handlers in same transaction with saving event. They use repositories also:

// transaction starts... some handlers are used
eventRepository.save(event);
// some additional handlers2 are used
// transaction ends

If handlers2 contains any repository operation with independent entity, for example:

profileRepository.findAll();
// or
profileRepository.findByEmail("anyEmail");

, it fails with exception org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.nextiva.calendar.entity.Attendee. It seems Attendee collection should be saved because it was not.

To fix the issue I've used workaround like:

// transaction starts... some handlers are used
attendeeRepository.save(event.getAttendees());
eventRepository.save(event);
// some additional handlers2 are used
// transaction ends

It works now, but I do not like this way.

Questions:

  1. Is it my architectural issue?
  2. Is it hibernate issue?
  3. How should it be configured without redundant calling attendeeRepository.save(event.getAttendees());?

Upvotes: 0

Views: 3712

Answers (1)

Cepr0
Cepr0

Reputation: 30429

Try to switch to JpaRepository and use

eventRepository.saveAndFlush(event);

instead of eventRepository.save(event).

Or

eventRepository.save(event);
eventRepository.flush();

It will force the repo to flush all pending changes to the database.


Also check whether you set @Transactional(readOnly = true) on your repo interface that turn the flush mode to NEVER (as described in the reference, or MANUAL as described here) also for save methods. Perhaps this is the issue...

Upvotes: 1

Related Questions