我创建了一个简单的测试用例,但我没有得到预期的行为。 我感兴趣为什么hibernate会选择更新父表(Country),尽管我为多对一关系提供了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;
hibernate 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);
我希望我在地址表中插入了一个新行,但我也获得了Country表的更新 - 唯一的行,该国家的名称变为斯洛文尼亚,而不是留在美国(预期的行为&lt; = update =“false”):
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的级联混淆,这解决了我所有的问题。
事情如下:Hibernate清楚地说:
更新,插入(可选 - 默认为 true):指定映射 列应包含在SQL中 UPDATE和/或INSERT语句。 将两者都设置为false允许纯粹 “派生”协会的价值是 从另一个属性初始化 映射到相同的列,或通过 触发器或其他应用程序。
。这意味着当在country属性上使用update =“false”时(在countryId上),我说要休眠你不能做UPDATE地址SET firstName =“x”,lastName =“y”, countryId = 123 哪里条件;仅在没有countryId的情况下进行更新 比我看到DB的ON UPDATE CASCADE引用父表(Country) - 如果Country更新,则更新子表(Address表中的countryId列)。与我认为hibernate的更新相反,我意识到通过提供cascade =“save-update”,我对hibebernate说,无论你在Address对象中对Country对象有什么值,都要在它自己的Country表中更新它们。所以解决方案是让cascade =“persist,merge”而没有save-update部分!
答案 0 :(得分:1)
在update = "false"
媒体资源上设置country
不允许您更新相应的countryId
字段,即为特定Country
选择其他Address
。< / p>
如果要禁用现有Country
名称的分类,则需要在相应的媒体资源上指定update = "false"
:
<class name="Country" table="Country" lazy="false">
...
<property name="name" type="string" not-null="true" length="100" update = "false" />
</class>