4

Given a Hibernate/JPA entity with cascading set to ALL for a related entity:

@Entity
public class Entity {
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "entity")
    private Set<RelatedEntities> relatedEntities;
}

Is it possible to temporarily turn off the cascading, e.g. to allow Entity to be persisted without also persisting its relatedEntities?

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • If you using cascade constraints you can persist Entity without checking constraints immediately afterwards using DEFERRABLE INITIALLY IMMEDIATE constraint. But on end of transaction you must save also relatedEntities. More: http://stackoverflow.com/questions/5300307/not-deferrable-versus-deferrable-initially-immediate – Mr Jedi Sep 15 '15 at 09:02
  • Thanks but not sure how that would be workable as the referenced article relates to a SQL keyword but the cascades are being managed by Hibernate? – Steve Chambers Sep 15 '15 at 09:23
  • cascades for sure are managed by db (if you not using create option by hibernate you must create them), I suspect hibernate also can validate constraints if you add annotations but I don't use them. If you want save Entity without relatedEntities, maybe db structure is improperly designed? – Mr Jedi Sep 15 '15 at 09:48
  • Maybe you should use another table for relations? – Mr Jedi Sep 15 '15 at 09:49
  • Of course db manage cascades. If you violate db contraint you will get for example ConstraintViolationException or DataIntegrityViolationException. – Mr Jedi Sep 15 '15 at 10:07
  • You can do simple tests to check that. Create Entity1 and Entity2, embed Entity2 in Entity1, create constraint with no action on delete. Save Entity2, save Entity1 with Entity2 and try delete Entity2 – Mr Jedi Sep 15 '15 at 10:07
  • 2
    @MrJedi You are talking about a completely different concept which is not related to the question at all. – Dragan Bozanovic Sep 15 '15 at 10:45

2 Answers2

1

You can't temporarily disable cascading (to my knowledge, at least), but since you use Hibernate you can insert new entity using HQL

String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
int createdEntities = s.createQuery( hqlInsert ).executeUpdate();

There is always a "manual" solution where you remember relatedEntities in a variable for later use, and set null value as its value on Entity instance before persisting it.

Predrag Maric
  • 23,938
  • 5
  • 52
  • 68
  • Would prefer to avoid the HQL solution as it isn't type safe and very brittle with regard to changing the entities. The "manual" solution sounds more promising if it works - would setting the relatedEntities to `null` not have the effect of removing them if they were present? – Steve Chambers Sep 15 '15 at 09:38
  • That's a different question than your original one, since it is about updating existing entities instead of inserting new ones. I would have to check, but since `RelatedEntity` is the owning side of the relation, as long as you don't set `null` to `RelatedEntity#entity` I think it should be fine. – Predrag Maric Sep 15 '15 at 09:43
  • Thanks, the original question was supposed to be quite wide ranging for all cascading operations. (Persist was just an example - sorry if I didn't make this clear). – Steve Chambers Sep 15 '15 at 09:46
  • You're right, on second read it is clear you meant all cascading operations, sorry. I would have shortened the answer to only "manual" suggestion if I read it right the first time :) – Predrag Maric Sep 15 '15 at 09:48
  • No worries, feel free to do that now as have accepted the answer based on the "manual" suggestion. – Steve Chambers Sep 15 '15 at 09:52
  • Thinking about this again, I think I would discourage my "manual" suggestion, as it could work in trivial cases but cause many problems otherwise. You could easily end up having synchronization problems between your entities and database. HQL may be sensitive to changing entities but it doesn't cascade anything which is what you need. Feel free to unaccept my answer. – Predrag Maric Sep 15 '15 at 10:19
1

No, it is not possible to do it, and at least according to my modest opinion, it would not be a good thing to do so either. When other developers look at the mappings and the code that does persist/merge/delete... they would expect the cascades to be applied and introduce the unexpected behavior if they oversee that the cascades are temporarily disabled somewhere else for the code they are about to change.

However, you can map to the same table a new entity class which does not have the fields that are cascaded. Then just use that entity in situations in which you don't want the cascades to be applied.

Dragan Bozanovic
  • 23,102
  • 5
  • 43
  • 110
  • The use case is a little hard to explain but basically an entity is being used as an intermediary to pass data from a UI operation. In this case, the related entities need to be reconstructed and persisted one by one rather than the normal case of cascading. The second suggestion may be workable - my only reservation is it would inevitably create some duplication but that may be mitigated by refactoring common parts into a parent class. – Steve Chambers Sep 15 '15 at 11:56