Skip to main content
5 of 6
Not a Struts2 problem
Roman C
  • 1
  • 33
  • 71
  • 194

JPA - Increment a numeric field through a sequence programmatically

I have a JPA 2 web application (Struts 2, Hibernate 4 as JPA implementation only).

The current requirement is to add a (non-id) numeric sequential field, filled for certain rows only, to an existing entity. When inserting a new row, based on a certain condition, I need to set the new field to its highest value + 1 or to NULL.

For example:

ID NEW_FIELD DESCRIPTION -------------------------------- 1 1 bla bla 2 bla bla <--- unmatched: not needed here 3 bla bla <--- unmatched: not needed here 4 2 bla bla 5 3 bla bla 6 4 bla bla 7 bla bla <--- unmatched: not needed here 8 5 bla bla 9 bla bla <--- unmatched: not needed here 10 6 bla bla 

In the good old SQL, it would be something like:

INSERT INTO myTable ( id, new_field, description ) VALUES ( myIdSequence.nextVal, (CASE myCondition WHEN true THEN myNewFieldSequence.nextVal ELSE NULL END), 'Lorem Ipsum and so on....' ) 

But I've no clue on how to achieve it with JPA 2.

I know I can define callbacks methods, but JSR-000317 Persistence Specification for Eval 2.0 Eval discourages some specific operations from inside it:

3.5 Entity Listeners and Callback Methods


- Lifecycle callbacks can invoke JNDI, JDBC, JMS, and enterprise beans.
- In general, the lifecycle method of a portable application should not invoke EntityManager or Query operations, access other entity instances, or modify relationships within the same persistence context.[43] A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.

[43] The semantics of such operations may be standardized in a future release of this specification.

Summarizing, yes to JDBC (!) and EJB, no to EntityManager and other Entities.


#EDIT

I'm trying to achieve the solution described in the answer from @anttix, but I'm encoutering some problem, so please correct me where I'm wrong.

Table

MyTable ------------------------- ID number (PK) NEW_FIELD number DESCRIPTION text 

Main Entity

@Entity @Table(name="MyTable") public class MyEntity implements Serializable { @Id @SequenceGenerator(name="seq_id", sequenceName="seq_id", allocationSize=1) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_id") private Long id; @OneToOne(cascade= CascadeType.PERSIST) private FooSequence newField; private String description /* Getters and Setters */ } 

Sub entity

@Entity public class FooSequence { @Id @SequenceGenerator(name="seq_foo", sequenceName="seq_foo", allocationSize=1) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_foo") private Long value; /* Getter and Setter */ } 

DAO

myEntity.setNewField(new FooSequence()); entityManager.persist(myEntity); 

Exception

Caused by: javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction.

[...]

Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: ERROR: relation "new_field" does not exist

[...]

Caused by: org.hibernate.exception.SQLGrammarException: ERROR: relation "new_field" does not exist

[...]

Caused by: org.postgresql.util.PSQLException: ERROR: relation "new_field" does not exist

What am I doing wrong ? I'm pretty new to JPA 2 and I've never used an entity not associated to a physical table... this approach is totally new to me.

I guess I need to put the @Column definition somewhere: how could JPA possibly know that the newField column (mapped through ImprovedNamingStrategy to new_field on the database) is retrieved through the value property of the FooSequence entity ?

Some pieces of the puzzle are missing.


EDIT

As asked in comments, this is the persistence.xml:

<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="MyService" transaction-type="JTA"> <jta-data-source>java:jboss/datasources/myDS</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/> <property name="hibernate.query.substitutions" value="true 'Y', false 'N'"/> <property name="hibernate.show_sql" value="true" /> <property name="format_sql" value="true" /> <property name="use_sql_comments" value="true" /> </properties> </persistence-unit> </persistence> 
Andrea Ligios
  • 50.4k
  • 29
  • 127
  • 256