1

yet another many-to-many Hibernate questions. I have the simplest possible many-to-many mapping as follows:

@Entity
public class Strategy implements Serializable {
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "STRATEGY_TO_GROUP", joinColumns = {@JoinColumn(name="STRATEGY_ID")}, inverseJoinColumns = {@JoinColumn(name = "STRATEGY_GROUP_ID")})
    private Set<StrategyGroup> groups;
...
}

And the opposite side of the relation as follows:

@Entity
public class StrategyGroup implements Serializable {

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "STRATEGY_TO_GROUP", joinColumns = {@JoinColumn(name="STRATEGY_GROUP_ID")}, inverseJoinColumns = {@JoinColumn(name = "STRATEGY_ID")})
    private Set<Strategy> strategies = new HashSet<Strategy>();

What I want to do now is empty both tables in the easiest possible way. I am trying following (em is my entityManager).

em.createQuery("delete from StrategyGroup sg").executeUpdate();
em.createQuery("delete from Strategy s").executeUpdate();

This gives me constraint violation on the @joinTable. On the other hand if I delete by em.remove(strategyGroup); ti works fine - the strategy group gets deleted and the @joinTable is updated correctly.

So how do I empty the table? Do I need to load the objects and delete them one by one?

Thanks for help.

Jan Zyka
  • 17,460
  • 16
  • 70
  • 118

1 Answers1

3

First of all, your mapping is wrong. One side of the association must be the owner side, and define the mapping of the association. The other must be the inserse side, and just use the mappedBy attribute:

@ManyToMany(fetch = FetchType.EAGER, mappedBy = "groups")
private Set<Strategy> strategies = new HashSet<Strategy>();

Second, you should really avoid EAGER fetching on a toMany association, and particularly on both sides: this will force Hibernate to load all the associated entities recursively, and has a good chance to load all the rows of both tables in memory each time you load one row.

Now to your question:

If you want to delete everything from both tables, you first need to make sure that the join table is empty, else some rows in one of the tables will still be referenced by a row of the join table, and it will obviosuly fail. To do that, the best option in your case is to use a SQL query to delete everything from the join table before executing the two HQL queries you already have.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Interesting. Will try. But first: with em.remove(strategyGroup) I see in log hibernate calling delete from strategy_to_group and then delete from strategygroup which is exactly what I would expect to happen with the batch delete ... it is really an accident? – Jan Zyka Jun 22 '12 at 09:22
  • Hmm, not sure... Try fixing the association mapping, and then removing a group, or removing a strategy. Remember that bulk update and delete queries completely bypass the session and the association machinery: they're just translated to SQL and executed. – JB Nizet Jun 22 '12 at 09:30
  • With that fixed association mapping I am unable to add Strategies to StrategyGroups anymore :) Could you point me to some piece of doc which proves the correctness of mapping you proposed? – Jan Zyka Jun 22 '12 at 09:40
  • http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#collections-bidirectional : *A many-to-many association is defined logically using the @ ManyToMany annotation. You also have to describe the association table and the join conditions using the @ JoinTable annotation. If the association is bidirectional, one side has to be the owner and one side has to be the inverse end (ie. it will be ignored when updating the relationship values in the association table)* – JB Nizet Jun 22 '12 at 09:53
  • But still - with the corrected mapping I am unable to add strategy to StrategyGroup and merge the strategygroup object. It has no effect. Object is not added. Any idea? – Jan Zyka Jun 22 '12 at 09:56
  • 1
    *(ie. it will be ignored when updating the relationship values in the association table)*: you must initialize the owner side of the association. Hibernate ignores the inverse side. So if you add a strategy to a group, you must also add the group to the strategy. It's a bidirectional association, and you have to maintain both sides. Hibernate only considers the owner side, and ignores the inverse side. – JB Nizet Jun 22 '12 at 10:00