Hibernate: обход сгенерированного идентификатора в некоторых случаях

У меня есть две сущности Родитель и Ребенок. Родитель может иметь только одного ребенка, поэтому он содержит внешний ключ ребенка.

Все ID генерируются пользовательской реализацией IdentifierGenerator. Для какой-то сущности я хочу установить идентификатор вручную. Так что я нашел способ в моем пользовательском IdentifierGenerator получить значение поля id.

Проблема в том, что генератор никогда не вызывается, когда идентификатор дочернего элемента был предварительно определен, а дочерний элемент еще не сохранен.

Файл parent-hbm.xml:

<hibernate-mapping default-cascade="all">
    <class name="com.ParentImpl" table="Parent" dynamic-insert="false" dynamic-update="false">
        <cache usage="read-write" />
        <id name="id" type="java.lang.Long" unsaved-value="null">
            <column name="ID" sql-type="BIGINT"/>
            <generator class="com.EntityIdGenerator">
            </generator>
        </id>
        <many-to-one name="child" class="com.ChildImpl" foreign-key="CHILDSC" cascade="all" lazy="false" fetch="select">
            <column name="CHILD_FK" not-null="true" sql-type="BIGINT" unique="true"/>
        </many-to-one>
    </class>
</hibernate-mapping>

файл child-hbm.xml:

<id name="id" type="java.lang.Long" unsaved-value="null">
    <column name="ID" sql-type="BIGINT"/>
    <generator class="com.EntityIdGenerator">
    </generator>
</id>

Как я могу изменить это поведение?

Любая идея?

Заранее спасибо.

2 ответа

Вместо использования генератора, пытались ли вы настроить его для ручных идентификаторов, а затем использовать перехватчик или прослушиватель событий, который генерирует значение для случаев, когда он не назначен вручную?

Сара

Вы можете использовать аннотацию @PrePersist для создания идентификатора, если у него его еще нет. Я был удивлен вашим комментарием, что это не может быть сделано с перехватчиками или слушателями событий, поэтому я решил попробовать это.

Вот пример того, как это сделать. У меня есть класс "Test", который имеет назначенный вручную идентификатор, а затем я реализовал метод @PrePersist, чтобы присвоить идентификатор значению hashCode(), если у него еще нет идентификатора. Вы можете заменить любую схему генерации вместо вызова hashCode().

@Entity 
@Table (name="Test")
public class Test{

    @Id
    @Column(name="id")    
    private String id;

    @Column(name="PROPERTY")
    private String property;

    public Test() {
    }

    ... // Other constructors, getters and setters

    @PrePersist
    void generateId() {
        if (id == null) {
            id = Integer.toHexString(hashCode());
        }
    }

Я протестировал как назначенные, так и неназначенные идентификаторы, создав новые сущности и обновив существующие, и не столкнулся с какими-либо проблемами.

Пример создания нового объекта:

Test assigned = new Test("assigned", "p1");
Test generate = new Test();
generate.setProperty("p2");         
manager.persist(assigned);
manager.persist(generate);
manager.getTransaction().commit();

Пример обновления существующего объекта:

Test update = manager.find(Test.class, "assigned");
actionUpdate.setProperty("imageUpdated");

Test update2 = manager.find(Test.class, "some-generated-id");
update2.setProperty("videoUpdated");

manager.getTransaction().commit();

Надеюсь это поможет.

Сара

Другие вопросы по тегам