【问题标题】:Persisting an entity when ID is null and automatically generated in the databaseID为空时持久化实体并在数据库中自动生成
【发布时间】:2015-02-20 00:55:06
【问题描述】:

我将 EclipseLink 与 JavaDB 一起使用,每次尝试持久化新用户实体时,都会收到与新用户实体的 ID 字段为空这一事实相关的错误。我知道它是空的——这应该是因为 ID 字段是作为数据库中的身份生成的。还是我错了?我尝试将@GeneratedValue 添加到实体中,但无论使用何种生成策略都会导致错误。我也看过hereherehere,但这些问题似乎与我的问题并不完全相关。下面的异常总是在调用 EntityManager.persist(user) 时发生。

我还尝试删除@NotNull 和@GeneratedValue,奇怪的是,它通过了persist 调用——但只是在提交时失败。据我所知,我已经做好了一切准备。所以问题是:为什么这个应用程序无法添加新用户,我需要做什么来修复它?

用户实体:

 @Entity(name = "User")
 @Table(name = "USERS")
 public class User implements Serializable {
     private static final long serialVersionUID = 1L;
     @Id
     @Basic(optional = false)
     @NotNull
     @Column(name = "IDENTIFIER", nullable = false,unique = true)
     private Long identifier;
     // class shortened for brevity
}

对应这个SQL Script:

create table "USERSDBADMIN".USERS
(
        IDENTIFIER BIGINT not null primary key GENERATED ALWAYS AS IDENTITY 
            (START WITH 0, INCREMENT BY 1),
        USERNAME VARCHAR(50) not null,
        EMAIL VARCHAR(150) not null,
        LASTLOGIN DATE default NULL
);

用户创建方法(来自 JPA 控制器):

public void create(User user) throws PreexistingEntityException, RollbackFailureException, Exception {
    EntityManager em = null;
    try {
        utx.begin();
        em = getEntityManager();
        em.persist(user);
        utx.commit();
    } catch (Exception ex) {
        try {
            utx.rollback();
        } catch (Exception re) {
            throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
        }
        if (findUser(user.getIdentifier()) != null) {
            throw new PreexistingEntityException("User " + user + " already exists.", ex);
        }
        throw ex;
    } finally {
        if (em != null) {
            em.close();
        }
    }
}

GenerationStrategy.Identity 错误(基本上说ID字段为空):

ex = (javax.validation.ConstraintViolationException) javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details.

GenerationStrategy.Sequence 错误(Table 和 Auto 产生相同的异常):

ex = (org.eclipse.persistence.exceptions.DatabaseException) Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException. Internal Exception: java.sql.SQLSyntaxErrorException: SEQUENCE 'SEQ_GEN_SEQUENCE' does not exist. Call: VALUES(NEXT VALUE FOR SEQ_GEN_SEQUENCE) Query: ValueReadQuery(sql="VALUES(NEXT VALUE FOR SEQ_GEN_SEQUENCE)")

【问题讨论】:

    标签: java jpa derby glassfish-4


    【解决方案1】:

    不要对使用GenerationType.IDENTITY 策略生成的@Id 属性使用@NotNull 约束。 问题是@NotNull 和其他JSR-303 约束在提交之前得到验证。 并且在提交完成之前,自动递增的标识符不可用。

    试试这个,不要再关心 ID 初始化了:

     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     @Column(name = "IDENTIFIER", nullable = false, unique = true)
     private Long identifier;
    

    【讨论】:

    • 这是一个更好的解决方案——我真的不再关心 ID 初始化了!我应该在发布之前尝试一下——但它确实有效。谢谢@Lukas!
    【解决方案2】:

    当我在标识符处使用自动增量时,我会这样做:

    User user = new User();
    user.setIdentifier((long) 0);// Assign 0 to ID for MSSQL/MySQL to properly auto_increment the primary key.
    user.setUserName("some name");
    ...
    

    用这个注解的id:

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @NotNull
    @Column(name = "ID")
    private Long id;
    

    【讨论】:

    • Welp 做到了。但是,天哪?为什么我必须设置 ID 字段?我的意思是 JPA 应该自动设置它。
    • 我不必设置 ID 字段 - 请参阅接受的答案。此外,将 ID 设置为零会导致事情变得棘手,因为我的标识符以零开头(请参阅 SQL)。 -1 可以工作,但我从未尝试过。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 2020-05-19
    • 1970-01-01
    • 2011-12-28
    • 2014-05-16
    • 2012-01-30
    • 2023-04-08
    相关资源
    最近更新 更多