7

I have an entity Bar:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "bar")
private Set<Foo> fooSet;

And an entity Foo:

@ManyToOne(optional = false)
@JoinColumn(name = "bar_id")
private Bar bar;

Hibernate creates the foreign key constraint on foo.bar -> bar.id but it doesnt specify ON DELETE CASCADE. Why not? And is there any ways to achieve it?

Alternatively I can add the ON DELETE CASCADE manually in the DB (and disable DDL generation), is this a good practice? And also, do I have to modify my code in some way to let Hibernate know that related records are deleted automatically by the database?

Thanks.

Update - this is my JPA/Hibernate/PostgreSQL configuration:

<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <constructor-arg>
        <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="org.postgresql.Driver" />
            <property name="url" value="jdbc:postgresql://localhost:5432/my_db" />
            <property name="username" value="my_username" />
            <property name="password" value="my_password" />
        </bean>
    </constructor-arg>
</bean>
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
    <property name="showSql" value="true" />
    <property name="generateDdl" value="true" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter" ref="jpaAdapter" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
    <property name="dataSource" ref="dataSource" />
</bean>

Update 2 - clarified what I mean: the foreign key constraint is created, but I'm wondering why it doesnt specify ON DELETE CASCADE (changed the original question accordingly)

satoshi
  • 3,963
  • 6
  • 46
  • 57

2 Answers2

6

Hibernate manages cascade operations itself manually. What is more, if you would make cascades on database, and not declare them in Hibernate (for performance issues) you could in some circumstances get errors. This is because Hibernate stores entities in its session cache, so it would not know about database deleting something in cascade.

When you use second-level cache, your situation is even worse, because this cache lives longer than session and such changes on db-side will be invisible to other sessions as long old values are stored in this cache.

I've read a bit Hibernate sources (really unpleasant experience) and I doubt it is under any circumstances possible to manage cascades on database side - there are too many assumptions made by Hibernate design that are incompatibile with DB reality.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223
  • Thank you @lechlukasz, I'll let Hibernate manage the cascading! – satoshi Mar 30 '12 at 10:28
  • 3
    Fair enough. The question is, what happens if I have cascading set up on both sides and remove some entity. Does JPA/Hibernate detect the cascade on DB side and just clean up his objects? Or does it press on with multiple DELETE statements, that will succed (0 rows deleted) but waste some time? I'm interested in the performance aspect in particular. – Jacek Prucia Apr 15 '15 at 16:22
1

Using

 cascade = CascadeType.ALL

causes hibernate to traverse this relationship if you perform any operation. It doesn't influence generated DLL.

If you want to delete all entities in fooSet add orphanRemoval attribute.

@OneToMany(cascade = CascadeType.ALL, mappedBy = "bar", orphanRemoval=true)

Also using

<property name="generateDdl" value="true" />

is good ONLY for development environment. Don't use it for production. (e.g. hibernate can't know how to change table schema if you for example rename a property/column wil create another column and maybe even drop the previous one).

František Hartman
  • 14,436
  • 2
  • 40
  • 60
  • 1
    Thank you @franthartm. Yes, I know this. I was wondering why Hibernate doesn't let PostgreSQL manage the cascade by default (surely it's much more performant). Or is there a way to achieve it? – satoshi Mar 27 '12 at 19:16
  • 4 years later, I ran into this problem and was able to solve it by letting Postgres handle cascades adding the CASCADE clause to the FK. – leojh May 04 '16 at 16:07