dann.dev
dann.dev

Reputation: 2494

SpringData/Hibernate @ManyToOne cascading automatically when it should not

Given two entities like so

@Entity
public class Thing {
  @ManyToOne
  private ThingType thingType;
  ...
}

@Entity
public class ThingType {
  private String name;
  ...
}

From everything I have read, the default cascade should be nothing so if I get a reference to a Thing thing, and change the name field of its ThingType, then using a JpaRepository<Thing, Long> call thingRepo.save(thing), I would expect the change to ThingTypes name not to be persisted.

However this is not the case and the change is persisted. I am not sure why this is happening? What I am missing here?

Relevant versions:

Upvotes: 0

Views: 203

Answers (2)

Amir Pashazadeh
Amir Pashazadeh

Reputation: 7322

Well cascading is something else, let me ask you something. Do following things:

Thing thing = session.get(Thing .class, someId);
thing.getThingType().setTitle("new title");

and nothing more, again you see hibernate updates thingType.

It is called dirty checking, as long as an entity is attached to an active hibernate session, and its persistence state changes hibernate automatically updates its associated row in database. Event without calling a save or update.

So what is cascade? Consider following case:

Thing myThing = new Thing();
ThingType myThingType = new ThingType();
myThing.setThingType(myThingType);
session.save(myThing);

if the association cascade type is not set, then you will get an exception, because you are referencing a transient thingType object. But if you set the cascade type to persist, then hibernate first saves the thingType and then saves the thing, and everything goes fine.

So remember, if you fetch an object, then update its properties in the same session, there is no need to call a update or saveOrUpdate method on hibernate session (or jpa entityManager) because it is already in attached state, and its state is traced by hibernate.

Upvotes: 1

Marcus K.
Marcus K.

Reputation: 1040

Well, I would have expected the same, but it seems that Hibernate has its own default behaviour. In the Hibernate forum someone asked almost the same question. The answer refers to the Hibernate "dirty check" feature, which will detect and perstst/merge the change. You might change that behaviour by using Hibernate's Cascade annotation.

Upvotes: 1

Related Questions