为什么hibernate允许更新父表,尽管update =“false”提供给多对一关系?

时间:2010-11-30 10:32:57

标签: hibernate parent-child

我创建了一个简单的测试用例,但我没有得到预期的行为。 我感兴趣为什么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部分!

1 个答案:

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