Reputation: 2559
i was just working on @EmbededId code, i want to do an auto increment before the entity is persisted, this is want to do without use of @GeneratedValue and an identity column,
below is the table with composite id,
create table TBL_EMPLOYEE_002(
ID integer,
COUNTRY varchar(50),
NAME varchar(50),
constraint PK_EMP_00240 primary key(ID,COUNTRY)
)
this is the code for Entity mapping,
@Entity
@Table(name="TBL_EMPLOYEE_002")
public class EmployeeEntitySix implements Serializable{
// contructor's
@EmbeddedId
private EmployeeIdTwo id;
@Column(name="NAME")
private String employeeName;
// getters and setter's
@PrePersist
public void incId(){
EntityManager em = null;
Query q = null;
EntityManagerFactory emf = null;
try{
emf = Persistence.createEntityManagerFactory("forPractise");
em = emf.createEntityManager();
q = em.createQuery("select max(e.id.employeeId) from EmployeeEntitySix e");
List list = q.getResultList();
Integer i = (list != null && list.size() > 0) ? Integer.valueOf(list.get(0).toString()) : 0;
this.getId().setEmployeeId(++i);
}catch(Exception e){
System.out.println("EXCETION WHILE INCREASING COUNTER...");
e.printStackTrace();
}finally{
if(em != null && em.isOpen()){
em.close();
}
if(getEmf() != null && getEmf().isOpen()){
getEmf().close();
}
}
}
This is the composite id mapping,
@Embeddable
public class EmployeeIdTwo implements Serializable{
@Column(name="ID")
private Integer employeeId;
@Column(name="COUNTRY",length=50)
private String empCountry;
// getters and setters
}
this code is of my main method, this main method is in some other class,
public static void main(String [] args){
EntityManagerFactory emf = null;
EntityManager em = null;
EntityTransaction tx = null;
try{
emf = Persistence.createEntityManagerFactory("forPractise");
em = emf.createEntityManager();
tx = em.getTransaction();
tx.begin();
EmployeeEntitySix employee = new EmployeeEntitySix(new EmployeeIdTwo("ZIMBABWE"), "Henry Olanga");
em.persist(employee);
....
}
Now the above code runs fine, whenever i persist the entity "EmployeeEntitySix", the method annotated with @PerPersist runs, which will first fetch the max id, increments its, set it into the id in the embeded entity and persist the entity.
Now my question is,
I am creating EntityManagerFactory twice, first in the main method, second time in the @PrePersist method in entity EmployeeEntitySix. So whether i can use the first Entitymanagerfactory created in main method in the entity EmployeeEntitySix while pre-persist, or else whether i can reuse the entitymanager created in first time in main method in the @PrePersist method in entity.
Just for information, I am using plain java environment, I am not using a Java EE container.
Upvotes: 0
Views: 981
Reputation: 302
Hibernate by default tries to persist all fields of an entity class or embedded id, including the field emf
, but it does not know how to persist a field of the type EntityManagerFactory
.
Of course it does not make sense to persist an EntityManagerFactory
. You could mark the field as @Transient
to prevent it from being persisted, but then you are just going to face different problems.
The injection of an EntityManagerFactory
with a @PersistenceUnit
annotation only works on CDI Beans and EJBs in applications that run on a Java EE-compliant application server. As you are using a main method, I assume that your example is a simple JSE program.
Furthermore you should not access EntityManager
s in lifecycle callback methods such as @PrePersist
. A quote from the JPA Specification (JSR 317: JavaTM Persistence API, Version 2.0):
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. A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.
I suggest that you keep the EntityManagerFactory
out of your embedded id class and also get rid of the incId
-Method. Instead you could execute the query to determine the new employeeId
in your main method, before calling persist
. This works fine as long as only one instance of the program works with the database. When there are multiple programs trying to insert new employees there could be race conditions where the two programs try to insert the same id.
In order to prevent this you can use a database sequence to generate the employeeId
, with the annotations @GeneratedValue
and @SequenceGenerator
. You find more information about id generation here: http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Sequencing
Upvotes: 1