Как я могу отобразить "insert='false' update='false'" на ключ-свойство составного идентификатора, который также используется в FK "один ко многим"?
Я работаю на базе устаревшего кода с существующей схемой БД. Существующий код использует SQL и PL/SQL для выполнения запросов к БД. Перед нами была поставлена задача сделать небольшую часть независимой от движка базы данных проекта (сначала все изменить в конце концов). Мы решили использовать файлы отображения Hibernate 3.3.2.GA и "*.hbm.xml" (в отличие от аннотаций). К сожалению, невозможно изменить существующую схему, потому что мы не можем регрессировать какие-либо устаревшие функции.
Проблема, с которой я сталкиваюсь, заключается в том, что я пытаюсь отобразить однонаправленное отношение "один ко многим", где FK также является частью составного PK. Вот классы и файл отображения...
CompanyEntity.java
public class CompanyEntity {
private Integer id;
private Set<CompanyNameEntity> names;
...
}
CompanyNameEntity.java
public class CompanyNameEntity implements Serializable {
private Integer id;
private String languageId;
private String name;
...
}
CompanyNameEntity.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.jboss.org/dtd/hibernate/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example">
<class name="com.example.CompanyEntity" table="COMPANY">
<id name="id" column="COMPANY_ID"/>
<set name="names" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
<key column="COMPANY_ID"/>
<one-to-many entity-name="vendorName"/>
</set>
</class>
<class entity-name="companyName" name="com.example.CompanyNameEntity" table="COMPANY_NAME">
<composite-id>
<key-property name="id" column="COMPANY_ID"/>
<key-property name="languageId" column="LANGUAGE_ID"/>
</composite-id>
<property name="name" column="NAME" length="255"/>
</class>
</hibernate-mapping>
Этот код прекрасно работает для SELECT и INSERT компании с именами. Я столкнулся с проблемой при попытке обновить существующую запись. Я получил BatchUpdateException и после просмотра журналов SQL я увидел, что Hibernate пытается сделать что-то глупое...
update COMPANY_NAME set COMPANY_ID=null where COMPANY_ID=?
Hibernate пытался отключить дочерние записи перед их обновлением. Проблема заключается в том, что это поле является частью PK и не может обнуляться. Я нашел быстрое решение заставить Hibernate не делать этого, добавив not-null='true' к элементу key в родительском отображении. Так что теперь, возможно, отображение выглядит так...
CompanyNameEntity.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.jboss.org/dtd/hibernate/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example">
<class name="com.example.CompanyEntity" table="COMPANY">
<id name="id" column="COMPANY_ID"/>
<set name="names" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
<key column="COMPANY_ID" not-null="true"/>
<one-to-many entity-name="vendorName"/>
</set>
</class>
<class entity-name="companyName" name="com.example.CompanyNameEntity" table="COMPANY_NAME">
<composite-id>
<key-property name="id" column="COMPANY_ID"/>
<key-property name="languageId" column="LANGUAGE_ID"/>
</composite-id>
<property name="name" column="NAME" length="255"/>
</class>
</hibernate-mapping>
Это отображение дает исключение...
org.hibernate.MappingException: Repeated column in mapping for entity: companyName column: COMPANY_ID (should be mapped with insert="false" update="false")
Моя проблема сейчас в том, что я пытался добавить эти атрибуты к элементу key-property, но это не поддерживается DTD. Я также попытался изменить его на элемент "ключ ко многим к одному", но это тоже не сработало. Так...
Как я могу отобразить "insert='false' update='false'" на ключ-свойство составного идентификатора, который также используется в FK "один ко многим"?
2 ответа
Я думаю, что вы ищете аннотацию:
public class CompanyName implements Serializable {
//...
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID", insertable = false, updatable = false)
private Company company;
И вы должны быть в состоянии использовать аналогичные отображения в hbm.xml, как показано здесь (в 23.4.2):
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/example-mappings.html
"Dino TW" предоставил ссылку на комментарий Hibernate Mapping Exception: повторяющийся столбец в отображении для сущности, которая имеет жизненно важную информацию.
Ссылка намекает на предоставление "inverse=true" в отображении набора, я попробовал, и это на самом деле работает. Это такая редкая ситуация, когда клавиши Set и Composite собираются вместе. Сделайте инверсию = true, мы оставляем вставку и обновление таблицы с ключом Composite для самостоятельной обработки.
Ниже может быть необходимое отображение,
<class name="com.example.CompanyEntity" table="COMPANY">
<id name="id" column="COMPANY_ID"/>
<set name="names" inverse="true" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
<key column="COMPANY_ID" not-null="true"/>
<one-to-many entity-name="vendorName"/>
</set>
</class>