Почему hibernate допускает обновление родительской таблицы, хотя update = "false" предоставляется для отношения "многие к одному"? - PullRequest
0 голосов
/ 30 ноября 2010

Я создал простой пример для тестирования и не получил ожидаемого поведения. Меня интересует, почему 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" без части сохранения-обновления!

1 Ответ

1 голос
/ 30 ноября 2010

Настройка update = "false" на country свойство не позволяет обновлять соответствующее поле countryId, т.е. выбрать другое Country для конкретного Address.

Если вы хотите отключитьПри изменении имени существующего Country необходимо указать update = "false" в соответствующем свойстве:

<class name="Country" table="Country" lazy="false"> 
    ...
    <property name="name" type="string" not-null="true" length="100" update = "false" /> 
</class> 
...