Showing posts with label persist. Show all posts
Showing posts with label persist. Show all posts

Monday, May 11, 2015

JPA exception: org.hibernate.PersistentObjectException: detached entity passed to persist

When I saved a collection of form data into database by using JPA, I got "detached entity passed to persist" error.

I have a CompanyClass entity, and inside CompanyClass entity, I have a one to one relationship to Filestore entity.  See detail relationship of these two entities at JPA relationship between entities.

The save method I wrote in my service impl is like following:

     @PersistenceContext   
     private EntityManager emgr; 
     @Override  
     @Transactional  
      public void saveClass(CompanyClass cclass)  
                throws Exception {  
           emgr.persist(cclass);  
           emgr.close();  
      }  


But when I ran it, I got exception: org.hibernate.PersistentObjectException: detached entity passed to persist.

After research, I found out I shouldn't use

 emgr.persist(cclass);  

Instead, I should use

  emgr.merge(cclass);  


I found a blog about JPA: persisting vs. merging entites . It is clear about when we should use persist, and when we should use merge.

In my case, it falls into this:

You want to insert a new entity that may have a reference to another entity that may but may not be created yet (relationship must be marked MERGE). For example, inserting a new photo with a reference to either a new or a preexisting album.


Wednesday, April 1, 2015

JPA Relationship between Entities

I have a CompanyClass table and each class can only have one image saved in the filestore table in the database. And the image file saved in Filestore table only match one Companyclass. I would like to use JPA to do data retrieving, saving and removing.


This is a OneToOne mapping relationship in JPA. My entities are like this.

  @Entity   
  @Table(name="COMPANYCLASS", schema="xxx")   
  public class CompanyClass implements Serializable {   
    private static final long serialVersionUID = 1L;   
    @Id   
    @GeneratedValue(strategy=GenerationType.IDENTITY)   
    @Column(name="CLASS_ID",unique = true, nullable = false)   
    private Long classId;   
    @OneToOne (targetEntity=FileStore.class, cascade = CascadeType.ALL)   
    @JoinColumn(name="IMG_ID", referencedColumnName="FILE_ID")   
    private FileStore fileStore; 
    @Column(name="FILE_NAME")   
    private String fileName; 
   ....
    (get and set methods)   
   ....   


 @Entity  
 @Table(name="FILESTORE", schema="xxxx")  
 public class FileStore implements Serializable {  
      private static final long serialVersionUID = 1L;  
      @Id  
      @GeneratedValue(strategy=GenerationType.IDENTITY)  
      @Column(name="FILE_ID" ,unique = true, nullable = false)  
      private Long fileId;  
      @OneToOne(mappedBy="fileStore")  
      private CompanyClass companyClasses;  
 ....  
 (get and set method)       
 ....  

I specified my table primary key to self-incremented in the database side. So I use
 @GeneratedValue(strategy=GenerationType.IDENTITY) 

In this example, my CompanyClass is  the owner. So in the FileStore entity, it is mappedBy ="fileStore". This fileStore is the attribute in the CompanyClass.


  @JoinColumn
A Join Column in JPA is a column in the owner side entity that refers to a key (usually a primary key) in the non-owner or inverse entity.

In the CompanyClass entity, I have
 cascade = CascadeType.ALL
 This means the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities.

For example, if I want to insert a new companyclass with an image into database, I can just write code like this.

  EntityManager emgr;  
  CompanyClass cclass = new CompanyClass();  
            FileStore fileStore= new FileStore();  
            fileStore.setFileName = "Image.png";  
            cclass.setFileStore(fileStore);       
  emgr.persist(cclass);  
  emgr.close();  


Wednesday, March 25, 2015

Solved: JPA persist cannot save anything to database and no exception

I am using Spring JPA to insert data into database. In the persistence.xml, I use JTA transaction type, instead of RESOURCE_LOCAL. This means we use JTA and container managed transactions. 

 <persistence-unit name="name-unit" transaction-type="JTA">  

During the development time, I had some difficulties to use persist to save data into database. Here are a few things I would like to share to  pay attention when we work on this.

1. Setup persistence.xml. The following is what I used. The highlighted ones were new added when the code didn't work.

 <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
 <persistence xmlns="http://java.sun.com/xml/ns/persistence"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"  
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">  
      <persistence-unit name="name-unit"           transaction-type="JTA">  
           <provider>org.hibernate.ejb.HibernatePersistence</provider>  
           <jta-data-source>java:/xxx/datasources/dsname</jta-data-source>  
           <class>xxx.model.Class</class>  
                 <exclude-unlisted-classes>false</exclude-unlisted-classes>  
           <properties>  
                <property name="connection.driver_class" value="com.ibm.db2.jcc.DB2Driver" />  
                <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect" />  
                <property name="hibernate.show_sql" value="true" />  
                <property name="hibernate.format_sql" value="true" />  
                <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />  
                <property name="hibernate.connection.charSet" value="UTF-8" />  
                <property name="hibernate.max_fetch_depth" value="5" />  
                <property name="hibernate.connection.clientProgramName" value="supsearch" />  
                <property name="hibernate.cache.use_second_level_cache" value="false" />  
                <property name="hibernate.cache.use_query_cache" value="false" />  
                <property name="hibernate.hbm2ddl.import_files_sql_extractor" value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor" />  
                <property name="hibernate.validator.apply_to_ddl" value="false" />  
                <property name="hibernate.validator.autoregister_listeners" value="false" />                      
                <property name="jboss.entity.manager.factory.jndi.name" value="java:/name-emf" />  
                <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />  
                <property name="hibernate.generate_statistics" value="true" />  
       </properties>  
      </persistence-unit>  
 </persistence>  


2. Setup Spring JTA Transaction Manager and other JTA information
Spring will automatically discover the underlying JTA implementation.
We need to add JTA Transaction Manager into applicationContext.xml, in my case it is called web-persistence.xml.


 <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
 <beans xmlns="http://www.springframework.org/schema/beans"   
      xmlns:context="http://www.springframework.org/schema/context"   
      xmlns:jee="http://www.springframework.org/schema/jee"   
      xmlns:tx="http://www.springframework.org/schema/tx"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://www.springframework.org/schema/beans   
           http://www.springframework.org/schema/beans/spring-beans.xsd       
           http://www.springframework.org/schema/context   
           http://www.springframework.org/schema/context/spring-context.xsd       
           http://www.springframework.org/schema/jee   
           http://www.springframework.org/schema/jee/spring-jee.xsd       
           http://www.springframework.org/schema/tx   
           http://www.springframework.org/schema/tx/spring-tx.xsd">  
      <!-- Note: imported by SecurityConfig.java -->  
  <context:mbean-export/>  
      <jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/name-unit" expected-type="javax.persistence.EntityManagerFactory" />  
      <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">  
           <property name="persistenceUnits">  
                <map>          
                     <entry key="name-unit" value="persistence/name-unit" />  
                </map>  
           </property>  
           <property name="persistenceContexts">  
                <map>  
                     <entry key="name-unit" value="persistence/name-context"/>  
                </map>  
           </property>  
      </bean>  
      <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">  
           <property name="entityManagerFactory" ref="entityManagerFactory" />  
      </bean>  
      <tx:annotation-driven/>       
      <tx:jta-transaction-manager/>  
 </beans>  

3. Injection via @PersistenceContext

The EntityManager itself is created by the container using the information in the persistence.xml, so to use it at runtime, we simply need to request it be injected into one of our components. We do this via @PersistenceContext.

@PersistenceContext should put into DAO impl. In my case it is called repository impl.

 @Repository  
 public class XxxxClassRepositoryImpl implements  
           XxxxClassRepository, Serializable {  
      private static final long serialVersionUID = 1L;  
      @PersistenceContext   
      private EntityManager emgr;  


4. Add @Transactional Annotation 

In the DAO impl layer and service impl layer (if you have), we need to add @Transcational annotation in. This annotation can be added in the class level and method level.

  @Repository   
  @Transactional  
  public class XxxxClassRepositoryImpl implements   
       XxxxClassRepository, Serializable {   
    private static final long serialVersionUID = 1L;   
    @PersistenceContext    
    private EntityManager emgr;   


If you want to learn how Spring transactional really work, I found this blog is very helpful.
http://blog.jhades.org/how-does-spring-transactional-really-work/