Why JPA persist() does not generated auto-increment primary ID?
Asked Answered
A

3

7

I'm using JPA toplink-essential and SQL Server 2008

My goal is to get auto-increment primary key value of the data that is going to be inserted into the table. I know in JDBC, there is getInsertedId() like method that give you the id of auto-increment primary id (but that's after the insert statement executed though)

In JPA, I found out @GenratedValue annotation can do the trick.

@Entity
@Table(name = "tableOne")
public class TableOne implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "tableId")
    private Integer tableId;

Now if I run the code below it should give me the auto incremented id but it returns NULL...

 EntityManager em = EmProvider.getInstance().getEntityManagerFactory().createEntityManager();
 EntityTransaction txn = em.getTransaction();
 txn.begin();

 TableOne parent = new TableOne();
 em.persist(parent); //here I assume that id is pre-generated for me.
 System.out.println(parent.getTableId()); //this returns NULL :(
Abrahamabrahams answered 2/2, 2011 at 4:46 Comment(6)
I can get obtained id if I commit: em.getTransaction().commit() but there is no way to get id already with persist??? hmmAbrahamabrahams
Your code should work as you expect. I tested it and I get the id before committing or if I then rollback. Strange that it doesn't.Hagiographer
Does it make any difference if tableId is an int rather than an Integer?Hagiographer
@Joel: just to make sure are you using SQL Server?Abrahamabrahams
I switched type from "Integer" to "int" and now parent.getTableId() is returning 0 (with @GeneratedValue.SEQUENCE) though it shouldn't be 0, not sure why.Abrahamabrahams
It's a default value of int type and nothing to do with database or JPA.Oppress
O
2

We are also using SQL Server 2008 and it never worked for me so I always execute separate query "SELECT @@IDENTY" to get the inserted id.

The reason I found on the net was that auto id (IDENTITY) is managed by database and never fetched in Entity until unless you commit the row or manually retrieve the info from database.

Oppress answered 2/2, 2011 at 9:31 Comment(3)
Do you mean because SQL Server 2008, we can't use @GeneratedValue.Sequence or Table or Identity ??? I figured I had to flush first (insert call to db to get generated id) but my goal is without insert call if I can get primary id.Abrahamabrahams
You may be correct, the doc doesn't seems to list SQL Server to support SEQUENCE object.... "Sequence objects use special database objects to generate ids. Sequence objects are only supported in some databases, such as Oracle, DB2, and Postgres." en.wikibooks.org/wiki/Java_Persistence/…Abrahamabrahams
marking as an answer, SEQUENCE is not being supported by SQL ServerAbrahamabrahams
G
12

The problem is you are using IDENTITY id generation. IDENTITY id generation cannot do preallocation as they require the INSERT to generate the id. TABLE and SEQUENCE id generation support preallocation, and I would always recommend usage of these, and never using IDENTITY because of this issue and because of performance.

You can trigger the id to be generated when using IDENTITY id generation by calling flush().

Growing answered 2/2, 2011 at 15:16 Comment(3)
hmmm sequence not working for me. I changed my annotation in entity class to: @Id @SequenceGenerator(name="seq", sequenceName="seq") @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")Abrahamabrahams
Then after em.persist(myBean); int insertedId = myBean.getId(); This getId() is returning null... am i doing something wrong?Abrahamabrahams
That is a timing problem. JPA did not insert the data when you try to get the id value. You must flush to make him start doing the modifications on the database. Afterwards you have the id. Better would be that JPA does the modifications on the db when you call getId().Kerguelen
F
6

just simply do this :

public void create(T entity) {
   getEntityManager().persist(entity);
   getEntityManager().flush();
   getEntityManager().refresh(entity);
}

After refreshing the entity you have the ID field with proper value.

Footmark answered 18/7, 2012 at 6:5 Comment(1)
The reason for adding the flush() is that persist() is not clearly guaranteed to have generated the @GeneratedValue, but it must be generated at or before the flush(). See this question: #9088348Trisoctahedron
O
2

We are also using SQL Server 2008 and it never worked for me so I always execute separate query "SELECT @@IDENTY" to get the inserted id.

The reason I found on the net was that auto id (IDENTITY) is managed by database and never fetched in Entity until unless you commit the row or manually retrieve the info from database.

Oppress answered 2/2, 2011 at 9:31 Comment(3)
Do you mean because SQL Server 2008, we can't use @GeneratedValue.Sequence or Table or Identity ??? I figured I had to flush first (insert call to db to get generated id) but my goal is without insert call if I can get primary id.Abrahamabrahams
You may be correct, the doc doesn't seems to list SQL Server to support SEQUENCE object.... "Sequence objects use special database objects to generate ids. Sequence objects are only supported in some databases, such as Oracle, DB2, and Postgres." en.wikibooks.org/wiki/Java_Persistence/…Abrahamabrahams
marking as an answer, SEQUENCE is not being supported by SQL ServerAbrahamabrahams

© 2022 - 2024 — McMap. All rights reserved.