【问题标题】:How to Stop Hibernate From Trying to Update one-to-many Over Join Table如何阻止 Hibernate 尝试更新一对多 Over Join 表
【发布时间】:2010-06-29 16:43:35
【问题描述】:

好的,我的 Hibernate 映射和获得所需的行为有点问题。

基本上我拥有的是以下 Hibernate 映射:

<hibernate-mapping>
    <class name="com.package.Person" table="PERSON" schema="MYSCHEMA" lazy="false">
        <id name="personId" column="PERSON_ID" type="java.lang.Long">
            <generator class="sequence">
                <param name="sequence">PERSON_ID_SEQ</param>
            </generator>
        </id>

        <property name="firstName" type="string" column="FIRST_NAME">
        <property name="lastName" type="string" column="LAST_NAME">
        <property name="age" type="int" column="AGE">

        <set name="skills" table="PERSON_SKILL" cascade="all-delete-orphan">
            <key>
                <column name="PERSON_ID" precision="12" scale="0" not-null="true"/>
            </key>
            <many-to-many column="SKILL_ID" unique="true" class="com.package.Skill"/>
        </set>
    </class>
</hibernate-mapping>


<hibernate-mapping>
    <class name="com.package.Skill" table="SKILL" schema="MYSCHEMA">
        <id name="skillId" column="SKILL_ID" type="java.lang.Long">
            <generator class="sequence">
                <param name="sequence">SKILL_ID_SEQ</param>
            </generator>
        </id>
        <property name="description" type="string" column="DESCRIPTION">
    </class>
</hibernate-mapping>

假设我已经在技能表中填充了一些技能。现在,当我创建一个新人员时,我想通过设置技能的 ID 将它们与技能表中已经存在的一组技能相关联。例如:

Person p = new Person();
p.setFirstName("John");
p.setLastName("Doe");
p.setAge(55);

//Skill with id=2 is already in the skill table
Skill s = new Skill()
s.setSkillId(2L);

p.setSkills(new HashSet<Skill>(Arrays.asList(s)));
PersonDao.saveOrUpdate(p);

如果我尝试这样做,但我会收到一条错误消息:

WARN (org.slf4j.impl.JCLLoggerAdapter:357) - SQL Error: 1407, SQLState: 72000
ERROR (org.slf4j.impl.JCLLoggerAdapter:454) - ORA-01407: cannot update ("MYSCHEMA"."SKILL"."DESCRIPTION") to NULL

ERROR (org.slf4j.impl.JCLLoggerAdapter:532) - Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update

我认为我收到此错误的原因是因为 Hibernate 发现 ID 为 2 的技能已将其描述“更新”为 null(因为我从未设置它)并尝试更新它。但我不希望 Hibernate 更新它。我想要它做的是插入新的人 p 并将一条记录插入到联接表 PERSON_SKILL 中,该记录将 p 与 id=2 的 SKILL 表中的技能匹配,而无需触及 SKILL 表。

有没有办法实现这种行为?

【问题讨论】:

    标签: java hibernate insert one-to-many


    【解决方案1】:

    而不是自己创建技能对象:

    //Skill with id=2 is already in the skill table
    Skill s = new Skill()
    s.setSkillId(2L);
    p.setSkills(new HashSet<Skill>(Arrays.asList(s)));
    

    您应该从 Hibernate Session 中检索它:

    Skill s = (Skill) session.get(Skill.class, 2L);
    p.setSkills(new HashSet<Skill>(Arrays.asList(s)));
    

    这样Session认为p.skills中包含的技能是persistent, and not transient

    【讨论】:

    • 技能不是暂时的(这会导致插入),它在数据库中有一个表示,它有一个标识符值。
    • 那么它会被贴上什么标签——“分离”?我认为解决方案是一样的。
    • @Pascal Thivent:是的,他的实现与您加载所需技能并将其添加到人员的技能集(似乎相同)的答案有何不同?我是否缺少一些区别,因为 matt b 的解决方案是我将如何解释您的解决方案。
    【解决方案2】:

    这可能是可能的如果你没有级联all-delete-orphan,它明确告诉hibernate 级联更改。

    但正确的方法是 IMO 从数据库中加载所需的 Skill 实体并将其添加到 Person 的技能集中。

    【讨论】:

    • 好的,所以删除 all-delete-orphan 是可行的,但这里的最佳做法是什么?首先检索技能并将其与我的人员关联或删除级联属性?
    • 好吧,在某些情况下,您仍然想从级联中受益,没有级联不是一个好的解决方案:) 所以我会先从数据库中加载技能。
    猜你喜欢
    • 1970-01-01
    • 2018-10-21
    • 2016-09-13
    • 2010-09-18
    • 2013-07-16
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 2018-03-26
    相关资源
    最近更新 更多