Я создал простой пример для тестирования и не получил ожидаемого поведения. Меня интересует, почему hibernate выбирает обновить родительскую таблицу (Страна), хотя я предоставляю атрибут update = "false" для отношения многие-к-одному (в Address.hbm.xml)?
DDL:
CREATE TABLE Country (
`id` smallint NOT NULL auto_increment,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) TYPE=InnoDB AUTO_INCREMENT=0;
CREATE TABLE Address (
`id` bigint NOT NULL auto_increment,
`firstName` varchar(100) NOT NULL,
`lastName` varchar(100) NOT NULL,
`countryId` smallint NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (countryId)
REFERENCES Country(id)
ON UPDATE CASCADE ON DELETE RESTRICT
) TYPE=InnoDB AUTO_INCREMENT=0;
Спящий xmls:
<class name="Country" table="Country" lazy="false">
<id name="id" column="id" type="integer">
<generator class="native" />
</id>
<property name="name" type="string" not-null="true" length="100"/>
</class>
<class name="Address" table="Address" >
<id name="id" column="id" type="long" unsaved-value="-1">
<generator class="native" />
</id>
<property name="addressFirstName" column="firstName" type="string" not-null="true" length="100"/>
<property name="addressLastName" column="lastName" type="string" not-null="true" length="100"/>
<!-- Country is parent table, Address is child table (holds the FK countryId).
From MySQL:
CASCADE: Update the row from the parent table and automatically update the matching rows in the child table.
RESTRICT: Rejects the delete operation for the parent table.
From hibernate:
1. cascade (optional): specifies which operations should be cascaded from the parent object to the associated object.
2. update, insert (optional - defaults to true): specifies that the mapped columns should be included in SQL UPDATE
and/or INSERT statements. Setting both to false allows a pure "derived" association whose value is initialized
from another property that maps to the same column(s), or by a trigger or other application.
-->
<many-to-one name="country" class="Country" column="countryId"
not-null="true" cascade="persist,merge,save-update" update="false" />
<many-to-one name="state" class="State" column="stateId"
cascade="persist,merge,save-update" update="false" />
</class>
В таблице "Моя страна" есть одна строка (id = 1):
INSERT INTO Country (name) VALUES ("United States");
ЕслиЯ делаю следующее:
Country country = getCountryFrom("US");
Address address = new Address();
address.setAddressFirstName("Deksa");
address.setAddressLastName("Jakim");
country.setName("Slovenia");
address.setCountry(country);
address.setId(-1);
saveAddress(address);
session.saveOrUpdate(address);
Я ожидаю, что в таблицу адресов была вставлена одна новая строка, но я также получаю обновление таблицы страны - единственная строка, название страны становится Словения,вместо того, чтобы оставаться в Соединенных Штатах (ожидаемое поведение <= update = "false"): </p>
Hibernate: select country0_.id as id6_, country0_.name as name6_ from Country country0_ where country0_.stringId='US'
Hibernate: insert into Address (firstName, lastName, countryId) values (?, ?, ?)
Hibernate: update Country set name=? where id=?
Так почему hibernate обновляет родительскую таблицу, когда не указывается?
С уважением,
Деспот
Редактировать: Вскоре после написания этого поста я понял, что путаю каскад БД с каскадом гибернации, и это решает все мои проблемы.
Дело в следующем:Hibernate четко говорит:
обновить, вставить (опtional - по умолчанию true): указывает, что сопоставленные столбцы должны быть включены в операторы SQL UPDATE и / или INSERT.Установка обоих в false допускает чистую «производную» ассоциацию, значение которой инициализируется из другого свойства, которое отображается в тот же столбец (столбцы), или с помощью триггера или другого приложения.
.Это означает, что при использовании update = "false" для свойства страны (для countryId) я говорю, что в спящем режиме вы не можете выполнить ОБНОВЛЕНИЕ адреса SET firstName = "x", lastName = "y", countryId = 123 где состояние;Выполняйте только обновление без countryId.
Чем я видел, что ON UPDATE CASCADE БД ссылается на родительскую таблицу (Страна) - если Страна была обновлена, чем обновлять дочернюю таблицу (столбец countryId в таблице адресов).Вопреки тому, что я думал, что обновление hibernate подойдет, я понял, что, предоставляя cascade = "save-update", я говорю hibebernate: все значения, которые вы имеете для объекта Country в объекте Address, обновляют их в своей собственной таблице Country.Таким образом, решение состояло в том, чтобы использовать cascade = "persist, merge" без части сохранения-обновления!