@Id @GenerateValue 但设置自己的ID值

问题描述 投票:0回答:5

我有一个带有生成ID的表,但在某些情况下我想自己设置它。我可以以某种方式强制 Hibernate 忽略 @GenerateValue 吗?

java hibernate jpa
5个回答
8
投票

这可能有点过头了,但你有没有想过编写自己的 CustomIDGenerator ,它可能是 hibernate 的 AutoGenerator 的子类,并公开了一些方法,你可以在其中设置要生成的下一个类对象的 id ,例如

class MyGenerator extends .... {

public void setIdForObject(Class clazz, Long id) {
    //once you use this API, the next time an object of 
    //type clazz is saved the id is used
}

public void setIdForObject(Class clazz, Long id, Matcher matcher) {
    //once you use this API, the next time an object of 
    //type clazz is saved and the matcher matches yes the id will be 
    //assigned. Your matcher can match properties like name, age etc
    //to say the matched object
}
}

这可能会变得复杂,但至少按照 hibernate doco

是可能的

8
投票

创建您自己的标识符生成器/序列生成器

public class FilterIdentifierGenerator extends IdentityGenerator implements IdentifierGenerator{

@Override
public Serializable generate(SessionImplementor session, Object object)
        throws HibernateException {
    // TODO Auto-generated method stub
    Serializable id = session.getEntityPersister(null, object)
            .getClassMetadata().getIdentifier(object, session);
    return id != null ? id : super.generate(session, object);
}

}

将您的实体修改为:

@Id
@GeneratedValue(generator="myGenerator")
@GenericGenerator(name="myGenerator", strategy="package.FilterIdentifierGenerator")
@Column(unique=true, nullable=false)
private int id;
...

并且在保存时不要使用

persist()
使用
merge()
update()


7
投票

虽然这个问题很久以前就被问到了,但我在@lOranger的这篇文章中找到了完美的答案,并想分享它。

此提案检查对象的当前 id 是否设置为

null
以外的其他内容,如果是,则使用它,否则,它使用默认(或配置的)生成策略生成它。

它简单、直接,解决了@Jens 提出的无法检索对象当前 ID 的问题。

我刚刚实现了它(通过扩展 UUIDGenerator),它的工作方式就像一个魅力 :-D


2
投票

对于您的用例,您可以手动添加此无用户。 一种方法是将插入操作放在名为“./import.sql”的文件(在类路径中)上。 Hibernate会在SessionFactory启动时执行这些语句。


0
投票

@rakesh 的解决方案自 hibernate 6.2 起不起作用 https://discourse.hibernate.org/t/hybrid-id- Generation-in-hibernate-6-2-is-difficult/7666

我找到了 hibernate 6.4.4.Final 的解决方案

public class AssignedOrIdentityGenerator extends IdentityGenerator implements BeforeExecutionGenerator {

    @Override
    public Object generate(SharedSessionContractImplementor session, Object entity, Object currentValue, EventType eventType) {
        return getId(entity, session);
    }

    private static Object getId(Object entity, SharedSessionContractImplementor session) {
        return session.getEntityPersister(null, entity)
                .getIdentifier(entity, session);
    }

    /**
     * @implNote Method {@link #generate(SharedSessionContractImplementor, Object, Object, EventType)}
     * is called if this method returns false
     */
    @Override
    public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
        Object id = getId(entity, session);
        return isNull(id);
    }

    @Override
    public boolean generatedOnExecution() {
        // This method is called to configure a context (using this Generator) without knowledge of a specific Entity.
        // The choice for the real Entity must be made in the this.generatedOnExecution(entity, session) method.
        // For example, find out comment "support mixed-timing generators" in IdentifierGeneratorUtil.class (hibernate-core):
        // true is required, if ID sometimes should be generated by RDBMS (for example by AUTO_INCREMENT)
        return true;
    }
}

这个类完全取代了@rakesh的

FilterIdentifierGenerator
,其余代码可以保持不变。该类适用于
AUTO_INCREMENT / IDENTITY
数据库列。

如果您想使用

TABLE
SEQUENCE
UUID
id 生成类型,您可以使用我在here描述的类。然后你可以包装所需的“before”和“on”sql语句执行id生成器实现

class AssignedOrIdentityGenerator extends BeforeOrOnExecutionGenerator {
    public AssignedOrIdentityGenerator() {
        super(new Assigned(), new IdentityGenerator());
    }
}

使用 hibernate 6.4.4 您还可以创建简单的注释

@Retention(RUNTIME)
@Target({METHOD, FIELD})
@IdGeneratorType(AssignedOrIdentityGenerator.class)
public @interface AssignedOrGeneratedValue {
}

所以你可以替换这个代码片段

@Id
@GeneratedValue(generator = "assigned-or-generated")
@GenericGenerator(name = "assigned-or-generated", type = AssignedOrIdentityGenerator.class)
@Column(name = "id")
private Integer id;

用一个更简单的

@Id
@AssignedOrGeneratedValue
@Column(name = "id")
private Integer id;
© www.soinside.com 2019 - 2024. All rights reserved.