Используя PostgreSQL, почему Hibernate / JPA не создает каскадные ограничения? - PullRequest
7 голосов
/ 27 марта 2012

У меня есть объект Bar:

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

И объект Foo:

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

Hibernate создает ограничение внешнего ключа для foo.bar -> bar.идентификатор, но он не указывает ON DELETE CASCADE.Почему бы и нет?И есть ли способы добиться этого?

В качестве альтернативы я могу добавить ON DELETE CASCADE вручную в БД (и отключить генерацию DDL), это хорошая практика? И также, делатьМне нужно каким-то образом изменить свой код, чтобы Hibernate знал, что связанные записи автоматически удаляются из базы данных?

Спасибо.

Обновление - это мой JPA /Конфигурация Hibernate / PostgreSQL:

<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>

Обновление 2 - уточнил, что я имею в виду: ограничение внешнего ключа создано, но мне интересно, почему оно не указывает ON DELETE CASCADE (изменилОригинальный вопрос соответственно)

Ответы [ 2 ]

5 голосов
/ 29 марта 2012

Hibernate самостоятельно управляет каскадными операциями. Более того, если вы будете делать каскады в базе данных, а не объявлять их в Hibernate (из-за проблем с производительностью), в некоторых случаях вы можете получить ошибки. Это связано с тем, что Hibernate хранит сущности в своем кеше сеанса, поэтому он не будет знать о том, что база данных удаляет что-либо каскадно.

Когда вы используете кэш второго уровня, ваша ситуация еще хуже, потому что этот кэш живет дольше, чем сеанс, и такие изменения на стороне базы данных будут невидимы для других сеансов, поскольку в этом кэше хранятся длинные старые значения.

Я немного прочитал источники Hibernate (действительно неприятный опыт), и я сомневаюсь, что при любых обстоятельствах возможно управлять каскадами на стороне базы данных - слишком много предположений, сделанных в дизайне Hibernate, несовместимых с реальностью БД.

1 голос
/ 27 марта 2012

Использование

 cascade = CascadeType.ALL

приводит к тому, что hibernate пересекает эту связь, если вы выполняете какую-либо операцию.Это не влияет на сгенерированную DLL.

Если вы хотите удалить все сущности в fooSet, добавьте атрибут orphanRemoval.

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

Также использование

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

хорошо ТОЛЬКОдля среды разработки.Не используйте его для производства.(например, hibernate не может знать, как изменить схему таблицы, если вы, например, переименуете свойство / столбец, создадите другой столбец и, возможно, даже удалите предыдущий).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...