Как остановить Hibernate от попытки обновить таблицу соединений «один ко многим» - PullRequest
1 голос
/ 29 июня 2010

Хорошо, у меня возникли проблемы с отображениями 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>

Итак, давайтеПредположим, что я уже заполнил таблицу навыков с некоторыми навыками.Теперь, когда я создаю нового человека, я хочу связать его с набором навыков, которые уже существуют в таблице навыков, просто установив идентификатор навыка.Например:

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 видит, что навыкс идентификатором 2 «обновил» свое описание до нуля (так как я никогда не устанавливал его) и пытается обновить его.Но я не хочу, чтобы Hibernate обновлял это.Я хочу, чтобы он вставил новую персону p и вставил в таблицу соединения PERSON_SKILL запись, которая соответствует p с навыком в таблице SKILL с id = 2, не касаясь таблицы SKILL.

Isесть ли вообще такое поведение?

Ответы [ 2 ]

1 голос
/ 29 июня 2010

Это может быть возможно , если вы не каскадируете all-delete-orphan, который явно указывает на режим гибернации для каскадного изменения.

Но правильным способом было бы ИМО загрузить желаемую загрузкуSkill сущность из базы данных и добавление ее в набор умений Person.

1 голос
/ 29 июня 2010

Вместо того, чтобы создавать объект Skill самостоятельно:

//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:

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

Таким образом, сеанс считает, что навык содержится в p.skills является постоянным и не преходящим .

...