在 JPA @GeneratedValue列中手动指定主键的值

2022-09-01 07:49:12

我有一个实体,它有一个主键/ id字段,如下所示:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

这很有效。我正在使用EclipseLink创建DDL-Schema,并且列是正确创建的,如下所示:

`id` bigint(20) NOT NULL AUTO_INCREMENT

但是,我有几个实体,我确实想自己指定PK(这是一个小应用程序,将数据从旧数据库传输到我们正在构建的新数据库)。如果我指定POJO的ID(使用)并保留它,EclipseLink不会保存它(即记录被保存,但id是由eclipseLink自动生成的)。setId(Long id)

有没有办法手动指定具有@GeneratedValue的列的值?

以下是关于这个问题的一些想法:

我试图通过根本不使用@GeneratedValue来解决此问题,而只是手动定义要AUTO_INCREMENTed列。然而,这迫使我总是手动提供ID,因为EclipseLink会验证主键(因此它可能不是空,零或负数)。异常消息显示我应该指定eclipselink.id_validation,但是这似乎没有任何区别(我注释了,但仍然得到了相同的消息)。@PrimaryKey(validation = IdValidation.NONE)

澄清:我使用EclipseLink(2.4.0)作为持久性提供程序,我无法摆脱它(项目的大部分内容取决于eclipselink特定的查询提示,注释和类)。


编辑(回应答案):

自定义排序:我试图实现我自己的排序。我尝试了DefaultSequence的子类化,但EclipseLink会告诉我。但是我已经检查过了:类在类路径上。Internal Exception: org.eclipse.persistence.platform.database.MySQLPlatform could not be found

所以我子类化了另一个类,NativeSequence:

public class MyNativeSequence extends NativeSequence {

    public MyNativeSequence() {
        super();
    }

    public MyNativeSequence(final String name) {
        super(name);
    }


    @Override
    public boolean shouldAlwaysOverrideExistingValue() {
        return false;
    }

    @Override
    public boolean shouldAlwaysOverrideExistingValue(final String seqName) {
        return false;
    }

}

但是,我得到的是以下内容:

javax.persistence.RollbackException: Exception [EclipseLink-7197] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.ValidationException
Exception Description: Null or zero primary key encountered in unit of work clone [de.dfv.datenbank.domain.Mitarbeiter[ id=null ]], primary key [null]. Set descriptors IdValidation or the "eclipselink.id-validation" property.
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:102)
    ...
Caused by: Exception [EclipseLink-7197] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.ValidationException
Exception Description: Null or zero primary key encountered in unit of work clone [de.dfv.datenbank.domain.Mitarbeiter[ id=null ]], primary key [null]. Set descriptors IdValidation or the "eclipselink.id-validation" property.
    at org.eclipse.persistence.exceptions.ValidationException.nullPrimaryKeyInUnitOfWorkClone(ValidationException.java:1451)
    ...

(为清晰起见,缩短了堆栈跟踪)。这与我之前得到的信息相同。难道不应该子类 NativeSequence 吗?如果是这样,我不知道为Sequence或StandardSequence中的抽象方法实现什么。

还值得注意的是,只需对类进行子类化(而不覆盖任何方法)即可按预期方式工作。但是,将 false 换入根本不会生成单个值(我单步执行了程序,没有被调用一次)。shouldAlwaysOverrideExistingValue(...)getGeneratedValue()

此外,当我在事务中插入8个特定类型的实体时,它会导致数据库中有11条记录(到底是什么?!

编辑 (2012-09-01):我仍然没有问题的解决方案,实现我自己的序列并没有解决它。我需要的是一种方法,能够不显式设置Id(因此将自动生成)并能够显式设置Id(因此它将用于在数据库中创建记录)。

我试图将列定义为auto_increment自己并省略@GeneratedValue,但是验证将启动,不允许我保存这样的实体。如果我指定一个值 != 0 和 != 零,mysql 将报告重复的主键。

我没有想法和选择可以尝试。任何?(开始赏金)


答案 1

这适用于eclipselink。它将为序列创建一个单独的表,但这不会造成问题。

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id", insertable=true, updatable=true, unique=true, nullable=false)
private Long id;

GenerationType.AUTO将选择理想的生成策略。由于该字段被指定为可插入和可更新,因此将使用 TABLE 生成策略。这意味着 eclipselink 将生成另一个包含当前序列值的表,并生成序列本身,而不是将其委托给数据库。由于该列被声明为可插入,因此如果 id 在持久化时为 null,eclipselink 将生成该 id。否则,将使用现有 ID。


答案 2

如果您使用TABLE排序,那么EclipseLink将允许您覆盖该值(如果您的数据库支持此功能,则SEPECE将允许您覆盖该值,则MySQL不支持)。

对于IDENTITY,我甚至不确定MySQL是否允许您提供自己的Id,您可能希望对此进行验证。一般来说,我永远不会建议使用IDENTITY,因为它不支持预分配。

允许IDENTITY提供或不提供ID存在一些问题。一个是需要根据id值生成两个不同的插入SQL,至于ID,ID根本不能在插入中。您可能希望记录一个错误,以便为身份支持用户提供 ID。

您仍然应该能够让它与您自己的Serance子类一起使用,或者可能是MySQLPlatform子类。您将使用“eclipselink.target-database”持久性单元属性设置MySQLPlatform子类。


推荐