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

新手上路,请多包涵

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

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

这很好用。我正在使用 EclipseLink 创建 DDL-Schema,并且该列已正确创建,如下所示:

 `id` bigint(20) NOT NULL AUTO_INCREMENT

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

有没有办法手动指定具有 @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 中的抽象方法要实现什么。

还可能值得注意的是,简单地子类化(不覆盖任何方法)该类按预期工作。但是,在 shouldAlwaysOverrideExistingValue(...) 中返回 false 根本不会生成单个值(我逐步执行了程序并且 getGeneratedValue() 没有被调用一次)。

此外,当我在事务中插入 8 个某种类型的实体时,它会在数据库中产生 11 条记录(这到底是怎么回事?!)。

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

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

我的想法和选择都快用完了。任何? (开始赏金)

原文由 scravy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 703
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。

原文由 poison 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题