Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Persisting an entity when ID is null and automatically generated in the database

I'm using EclipseLink with JavaDB and every time I try to persist a new user entity I get an error relating to the fact the ID field of the new user entity is null. I know it's null -- and it should be because the ID field is generated as the Identity in the database. Or am I wrong? I've tried adding @GeneratedValue to the entity but that causes errors regardless of the generation strategy used. I've also looked here, here, and here but these questions don't seem to relate fully to my issue. The exceptions below always occur on at the call to EntityManager.persist(user).

I also tried removing @NotNull and @GeneratedValue and, oddly enough, it got past the persist call -- but only to fail on the commit. As far as I can tell I've got everything set right. So the question is: why is this application failing to add a new user and what do I need to do to fix it?

User entity:

 @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
}

Corresponding to this 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
);

User Create Method (from the JPA controller):

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 error (basically saying the ID field is null):

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 error (Table and Auto produce same exception):

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)")
like image 517
Richard Barker Avatar asked Dec 21 '14 21:12

Richard Barker


People also ask

What is a persistence entity?

Entities represent persistent data stored in a relational database automatically using container-managed persistence. They are persistent because their data is stored persistently in some form of data storage system, such as a database: they do survive a server failure, failover, or a network failure.

Which exception will be thrown by persist method?

(If the entity already exists, the EntityExistsException may be thrown when the persist operation is invoked, or the EntityExistsException or another PersistenceException may be thrown at flush or commit time.)


1 Answers

Do not use @NotNull constraint on @Id attribute generated using GenerationType.IDENTITY strategy. The problem is @NotNull and other JSR-303 constraints are validated before commit. And the autoincremented identifier isn't available until after the commit completes.

Try this and don't care about ID initialization any more:

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 @Column(name = "IDENTIFIER", nullable = false, unique = true)
 private Long identifier;
like image 133
Lukas Risko Avatar answered Oct 29 '22 20:10

Lukas Risko