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 :(
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().
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.
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.
Related
I have a MyEntity class with several columns one of which is an auto increment id. MyEntity looks like the following:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Basic(optional = false)
#Column(nullable = false)
private Long id;
When I create a new MyEntity and set all other columns (I do not set the id column), and then call persist:
MyEntity mn = new MyEntity("val1", "val2");
em.getTransaction().begin();
em.persist(mn);
em.getTransaction().commit();
em.close();
the following error occurs:
Query: DataModifyQuery(name="SEQUENCE" sql="UPDATE SEQUENCE SET
SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?")
Caused by: java.sql.SQLSyntaxErrorException: Table/View 'SEQUENCE' does not exist.
I tried to change the strategy of #GeneratedValue with no avail. There are plenty of similar issues online, but with no clear solution what to do in this case.
Do I need to assign a certain value to the id column in my new unmanaged entity? Do I need to setup specific values in the table where the id column is (I only set that it's a primary key)?
Use identity for generating ID by DB:
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
Do not add optional=false, nullable=false. Primary key will be never null in RDBS.
What database are you using?
https://docs.oracle.com/javaee/6/api/javax/persistence/GenerationType.html#AUTO states that the persistence provider will choose the most appropriate solution.
If you are using Hibernate, have you correctly set the dialect explicitly? Oftentimes I've seen Hibernate try to guess the correct dialect but get it wrong. This can cause a domino effect of the AUTO strategy being poorly chosen.
I'm using MS SQL Server + Hibernate (JPA, more precisely, with EntityManager) and i faced with the problem: I need to store entity into appropriate table in my DB; this table has uniqueidentifier as primary key; and storing entity already has UUID (it's primary key), with witch it should be inserted into the DB.
Problem is that when i try to merge my entity, hibernate do some magic and store my entity with another UUID value. So, when I fetch this entity from db and take a look on it ID, I see inappropriate value.
So, I want to tell hibernate not to do that (or, maybe, there is another solution?).
My entity class:
public class Entity extends BaseEntity {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(name = "id_column")
private UUID uuId;
// other fields, getters, setters
}
Also, I have one more 'annoyance': my IDE and my DB browser shows me another ID in that column. I mean, when I stop my app in the debug mode and look at the id of an entity, I see different value from a value in the database.
Thanks in advance!
I want to rewrite the call delete operation (on association table) on a many-to-many association sending by EclipseLink when we use only java code.
Let me explain the goal.
I have 3 tables, person, unit and an associative one : PerInUnit, so a person can be in multiple units and a units can contains many people. But I have some dependances on the PeInUnit table (If the person was present or not on a specific date, another table (Participations)), so I can't (and I don't want) delete a record. For that, I make softs deletes, so I can keep records to make some statistics.
I read already about the Customizer and AdditionalCriteria and I setted them to the PerInUnit class. It works perfectly => when I make an em.remove(myPerInUnit); the sql query sent to the db is Update PER_IN_UNIT SET STATUS='delete' WHERE id = #id; and the specified row as "delete" for status. Also, when I read all records, I don't have them with status "delete". But I use explicitly the PeeInUnit class.
Here is the code :
#Entity
#Table(name = "PER_IN_UNIT")
#AdditionalCriteria("this.status is null")
#Customizer(PIUCustomizer.class)
public class PerInUnit implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "GEN_SEQ_PIU")
#SequenceGenerator(name = "GEN_SEQ_PIU", sequenceName = "SEQ_PIU", initialValue = 1, allocationSize = 1)
#Column(name = "ID")
private Long id;
#ManyToOne(cascade=javax.persistence.CascadeType.PERSIST)
#JoinColumn(name = "PER_ID")
private Person person;
#ManyToOne(cascade=javax.persistence.CascadeType.PERSIST)
#JoinColumn(name = "UNI_ID")
private Unit unit;
#Column(name = "STATUS")
private String status;
//Constructor, getters, setters
}
And the code for the PIUCustomizer :
public class PIUCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) {
descriptor.getQueryManager().setDeleteSQLString("UPDATE PER_IN_UNIT SET STATUS = 'delete' WHERE ID = #ID");
}
}
Here come the problem : As I use EclipseLink with bidirectionnal relationship I want to make some instruction like myUnit.getPeople.remove(currentPerson); (remove the current person from the unit "myUnit"). But EclipseLink sent the following instruction (during commit !) :
DELETE FROM PER_IN_UNIT WHERE ((UNI_ID = ?) AND (PER_ID = ?))
instead of the
Update PER_IN_UNIT SET STATUS='delete' WHERE ((UNI_ID = ?) AND (PER_ID = ?))
that I expected and raise (obviously, because of dependances (FKs)) the following exception :
Query: DataModifyQuery(sql="DELETE FROM PER_IN_UNIT WHERE ((UNI_ID = ?) AND (PER_ID = ?))")
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:157)
at test.Crud.update(Crud.java:116)
at test.Test.runTest(Test.java:96)
at test.Test.main(Test.java:106)
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-02292: integrity constraint (PEOPLE.FK_PAR_PIU) violated - child record found
Other problem (in the same kind), when I make something like System.out.prinln(myUnit.getPeople()) I have all the people in the unit "myUnit", including them having status 'delete'.
Is it possible to change some code/instructions/Customizer/etc in eclipseLink to change the delete call from person for PerInunit table, or I have to make my own queries and use them instead of using powerful of orm ?
Thanks for your answers and please forgive me for my poor english !
Fab
You should not be getting a delete when you call myUnit.getPeople.remove(currentPerson) unless you mapped Unit to Person with a ManyToMany using the PER_IN_UNIT table. Since you have an entity for the PER_IN_UNIT table, this would be wrong, as it really should be a Unit-> PerInUnit OneToMany mapping and then a PerInUnit -> Person ManyToOne mapping. The myUnit.getPeople.remove(currentPerson) call would then simply be getting the PerInUnit instance and marking its status as deleted, or dereferencing it and letting JPA call remove, thereby using your soft delete SQL query.
By using a ManyToMany mapping for the PER_IN_UNIT table, this mapping is completely independent to your PerInUnit entity mapping, and knows nothing about the entities that maybe cached or the soft deletes required to remove them. If you don't want to map the PER_IN_UNIT table as an entity, see http://www.eclipse.org/forums/index.php/t/243467/ which shows how to configure a ManyToMany mapping for soft deletes.
I have parent and child entities with IDs that are generated using the strategy GenerationType.TABLE because I'm working with a MySQL database.
If I create the parent without specifying an ID (i.e., create the parent for the first time), add new children to it, and save the parent, then hibernate works as expected and uses the MySQL AUTO_INCREMENT column feature.
However, If I create a parent and specify an ID (i.e., instantiating a parent that has already been persisted), add a child to it, and save the child, then hibernate issues a select sequence_next_hi_value from hibernate_sequences ... and uses that as the child's PK.
Likewise, if I instantiate a parent by getting it from the database via session.get(Parent, 1), add a new child to it, and save either the parent or the child, then hibernate uses sequences to get the child's PK.
If I create enough new parents (32767, to be exact) to run up the mysql AUTO_INCREMENT counter, there would be failures due to the primary key not being unique enough.
Here are my parent and child entities (named Location and Category, respectively):
#Entity(name="location")
public class Location {
#Id #GeneratedValue(strategy=GenerationType.TABLE) #Column(name="location_id")
private int id;
#OneToMany(mappedBy="location")
#Cascade(CascadeType.SAVE_UPDATE)
private List<Category> categories;
...
}
#Entity(name="category")
public class Category {
#ID #GeneratedValue(strategy=GenerationType.TABLE) #Column(name="category_id")
private int id;
#ManyToOne #JoinColumn(name="location_id")
private Location location;
}
Here is the hibernate code:
Hibernate: select sequence_next_hi_value from hibernate_sequences where sequence_name = 'category' for update
Hibernate: update hibernate_sequences set sequence_next_hi_value = ? where sequence_next_hi_value = ? and sequence_name = 'category'
Hibernate: insert into category (location_id, category_id) values (?, ?)
Beforehand: I have no answer why hibernate uses another strategy when persisting your child record. But I may give you some answers or hints about the other issues you described:
Regarding the strategy GenerationType.TABLE, your application relies on the database functionality of generating an ID. This may cause database round-trips for each new database record inserted. When using an alternative strategy like hi-lo, the generator will reserve a bunch of ids (for example 100 or 1000) by contacting the database only once. This may improve performance greatly. On the other side, you may loose some ID when the application is restarted. If you may life with this issue hi-lo should be considered.
Another benefit of using a strategy not relying on a database product is, that if you switch databases you may keep your mappings.
I am using Hibernate 4.1.3 (JPA) on the Play! framework. The database is PostgreSQL 8.4.2. The schema was generated using hibernate.hbm2ddl.auto="update".
Short version: I have a class that has an #Id field that is a #GeneratedValue. Sometimes, when persisting it, I get a null-column violation, why?
More details:
I have a really simple class that I want to save to the database, that looks like this:
#Entity
class MyObject {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
#NotNull
public String email;
public Integer total;
}
I usually create an instance of MyObject, I assign a value to email and total fields while id is null and I save it via EntityManager.persist(). Hibernate gets an id for the new object and saves it to the DB.
However sometimes, I get the following stacktrace:
2012-05-19 00:45:16,335 - [ERROR] - from org.hibernate.engine.jdbc.spi.SqlExceptionHelper [SqlExceptionHelper.java:144] in play-akka.actor.actions-dispatcher-6
ERROR: null value in column "id" violates not-null constraint
2012-05-19 00:45:16,350 - [ERROR] - from application in play-akka.actor.actions-dispatcher-6
! #6ad7j3p8p - Internal server error, for request [POST /method] ->
play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[PersistenceException: org.hibernate.exception.ConstraintViolationException: ERROR: null value in column "id" violates not-null constraint]]
How is this possible? How can I track down the problem?
Here's the relevant DDL generated by Hibernate:
CREATE TABLE myobject (
id bigint NOT NULL,
email character varying(255) NOT NULL,
physical integer
);
CREATE SEQUENCE hibernate_sequence
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE ONLY dailydetailedscore
ADD CONSTRAINT dailydetailedscore_pkey PRIMARY KEY (id);
Try the annotation #org.hibernate.annotations.GenericGenerator(name = “test-hilo-strategy”, strategy = “hilo”):
#Id
#org.hibernate.annotations.GenericGenerator(name=“hilo-strategy”, strategy = “hilo”)
#GeneratedValue(generator = ”hilo-strategy”)
As someone noted above, AUTO does not do what you think. It uses the underlying DB to determine how to generate values. It may pick sequences (for oracle), identity column (for mssql), or something else that is db specific.
The approach here uses an internal strategy that Hibernate supplies called "hilo".
See chapter 5 of the Hibernate reference manual dealing with "Generator" for a full description of what each of the supplied ones does.
Neither the OP solution nor Matt's solution worked with my PostgreSQL 9.3.
But this one works:
#SequenceGenerator(name="identifier", sequenceName="mytable_id_seq", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="identifier")
Replace mytable_id_seq with the name of the sequence that generates your id.
Use Hibernate method:- save(String entityName, Object object)
Persist the given transient instance, first assigning a generated identifier.
Do not use :- #GeneratedValue(strategy=GenerationType.IDENTITY) for primary key if you want to persist user define Id.
For detail:-
http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/Session.html#save(java.lang.String
In mycase i was using Identity generation strategy and i have set the wrong data type in Postgres. Following steps i performed to debug the problem.
set
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true in application.properties and Drop the tables.
By this hibernate will automatically create the schema for you on the basis of your data-type.I noticed change in the datatype of id field.
Now when i tried any post requests, everything worked fine.