Showing posts with label JPA. Show all posts
Showing posts with label JPA. Show all posts

Tuesday, September 23, 2014

JPA 2.0 Native Query Result Mapping to a Bean or an Array

Working with JPA 2.0, I wanted to Construct a Bean (Array of Beans) by executing a Native Query.
Using the NamedQuery, we can declare the wanted new Bean, not necessarily an entity. This is done through this Declaration :

1
2
3
@NamedQuery(name="findPerson", 
 query = "SELECT new  org.nd.enterprise.bean.PersonDetail(e.personId, e.birthDate)"
   + " FROM Person p WHERE p.personId = :person")

We need to provide a constructor Containing exactly these parameters.

So Now coming back to the Native query. Sometime, the Query is quite complex so that we need to have it as Native Query. But in that case, it is not possible to declare the Bean inside the Query. And by using the below line we will get an error: org.hibernate.MappingException: Unknown entity: org.nd.enterprise.bean.PersonDetail


1
// Here we declare just a String query = "select ...."
List<PersonDetail> rec2 = entityManager.createNativeQuery(query,PersonDetail.class).getResultList();


This problem is resolved in JPA 2.1, see this post.
But in JPA 2.0, we may use this code :


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public List<PersonDetail> getPersonByEnterprise(String enterpriseId, List<String> personIds){
 @SuppressWarnings("unchecked")
 List<PersonDetail> records = entityManager.createNamedQuery("personDetailsByEnterprise").setParameter("enterpriseId", enterpriseId).setParameter("personIds", personIds).getResultList();
 List<PersonDetail> personRecords = new ArrayList<PersonDetail>();

 @SuppressWarnings("rawtypes")
 Iterator it = records.iterator( );

 while (it.hasNext( )) {
  Object[] result = (Object[])it.next(); // Iterating through array object 
     
  personRecords.add(new PersonDetail(result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7]));

     }
 return personRecords; 
  
}


So now, don't forget to create the appropriate constructor for PersonDetail.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public PersonDetail(Object enterprise_id, Object person_id, Object name,
   Object surname, Object profession, Object status, Object age, Object lunch_time) {

  
 this.enterpriseId = (String) enterprise_id;
 this.personId = (String) person_id;
 this.name = (String) name;
 this.surname =(String) surname;
 this.profession = (String) profession;
 if(status  != null ){
  this.status = StatusEnum.valueOf((String) status);
 }
 this.age = (Integer) age;
 this.lunchTime= (Date) lunch_time;
}

That's it, hope it helps you :).


Thursday, May 8, 2014

JPA Criteria API Queries (CriteriaBuilder, CriteriaQuery) Create Dynamic Query instead of appending String

Here is an example about how to create a Dynamic Query.


 This is very efficient when you have a method where some parameters may be null. so instead of creating a String builder (or String Buffer) and append the SQL Query, it is better to use the Criteria API Queries.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
public List<Devices> findDevice(String enterpriseId, List<String> modelIds, List<String> deviceIds, Date constructionDate) {
 
 CriteriaBuilder builder = entityManager.getCriteriaBuilder();
 CriteriaQuery<Devices> query = builder.createQuery(Devices.class);
 Root<Devices> deviceRoot = query.from(Devices.class);

 List<Predicate> predicateList = new ArrayList<Predicate>();
 if(enterpriseId !=null ){
  predicateList.add(builder.equal(deviceRoot.get("enterprise").get("enterpriseId"), enterpriseId));

 }
 if(modelIds != null && !modelIds.isEmpty()){
  predicateList.add(builder.isTrue(deviceRoot.get("deviceModel").get("modelId").in(modelIds)));
 }
 if(deviceIds != null && !deviceIds.isEmpty()){
  predicateList.add(builder.isTrue(deviceRoot.get("deviceId").in(deviceIds)));
 }

 predicateList.add(builder.greaterThan(deviceRoot.<Date>get("constructionDate"), constructionDate));

 query.where(builder.and(predicateList.toArray(new Predicate[predicateList.size()])));

   
 return entityManager.createQuery(query).getResultList();
}

Hope it helped you :) 

Wednesday, May 7, 2014

JPA Mapping Native Query to Bean (POJO, Class) other than the Entity JPA2.1

Working with JPA 2.0, every time I need to create a new bean (named PersonDetail) from the result of a query, I create a NamedQuery like this:


1
2
3
@NamedQuery(name="findPerson", 
 query = "SELECT new  org.nd.enterprise.bean.PersonDetail(e.personId, e.birthDate)"
   + " FROM Person p WHERE p.personId = :person")

A constructor with the desired output should be set in the PersonDetail bean.

But using the NativeQuery, this is not possible as the Query will be executed like it is given.
In fact while creating the query (NativeQuery or NamedQuery), we can fore the result to be the desired Bean, but this  will generate this error:



1
2
3
4
// Here we declare a @NamedNativeQuery   
List<PersonDetail> rec = entityManager.createNamedQuery("findPerson", PersonDetail.class).getResultList();
// Here we declare just a String query = "select ...."
List<PersonDetail> rec2 = entityManager.createNativeQuery(query,PersonDetail.class).getResultList();

org.hibernate.MappingException: Unknown entity: org.nd.enterprise.bean.PersonDetail

This is normal as it accepts only an Entity and not a Class (See this post to know how to fix that with JPA2.0). Fortenately JPA2.1 comes with the solution, by adding the @ConstructorResult in the @SqlResultSetMapping where you cone construct your Class (In JPA 2.0 only the Entity cn be specified and not another POJO .)




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 Query q = em.createNativeQuery(
      "SELECT personId, birthDate)"
   + " FROM Person p",
      "PersonDetailsResult");

   @SqlResultSetMapping(
       name="PersonDetailsResult",
       classes={
          @ConstructorResult(
               targetClass=org.nd.enterprise.bean.PersonDetail,
                 columns={
                    @ColumnResult(name="personId"),
                    @ColumnResult(name="birthDate")
                    }
          )
       }
      )

Sunday, March 30, 2014

JPA ManyToMany fix the Delete of records in Join table while Merging

I was working with a ManyToMany relation. But I have got problem while adding new records in the Association Table.




In fact I am working with three tables: the Person table is related to table Project using an association table lt_person_project.

Using ORM, the generated entities are :

In the Person Entity (it is the owner of this relation):

@ManyToMany(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
@JoinTable(name = "lt_person_project", schema = "enterprise_schema", joinColumns = { @JoinColumn(name = "person_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "project_id", nullable = false, updatable = false) })
public List getProjects() {
return this.projects;
}

In the Project Entity, we Have:
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "projects")
public List getPersons() {
return this.persons;
}


Now I have created the person, and while doing it, I have assigned to him some projects. I wanted then to assign him new projects, so the code was:

@Transactional(propagation= Propagation.REQUIRES_NEW)
public void assignProjectsToPerson(String personId, List projectIds) {
Person person = this.findPerson(personId);
List projects = projectDao.findProjects(projectIds);

        person.setProjects(projects);

entityManager.merge(person);

}

Doing so, Hibernate will first execute a query where it Delete all the rows in the association table where the personId is the one given by our method. Then it inserts the NEW records.

Thinking about my code, it is normal that I have such behavior, as I have told hibernate to setProjects. So I have ignored the old ones.

So in order to tell Hibernate that In fact I am adding new Records in the Association table, I have changed my setProject with this line:

person.getProjects().addAll(projects);

Even using this line, Hibernate will first delete the records then put them again, but at least, it will add the old and new ones.



Tuesday, March 25, 2014

JPA 2.0 Criteria Query/Builder DELETE : Typesafe DELETE queries

JPA 2.0 don't provide a dynamic way to write delete queries. In fact we can only write a type safe queries for the SELECT but not for the DELETE and Update.

JPA 2.1 provides this possibility using  CriteriaUpdate and CriteriaDelete. You can have more details in this link.


But actually, as I am obliged to use JPA 2.0 which comes with JBoss eap 6, and waiting for JPA 2.1, I should use the native queries.

So the problem here is that I have multiple lists that I should use in the query and that may be null.

Query query = entityManager.createNativeQuery("DELETE FROM person_record pr WHERE pr.person.person_id IN (select person_id from person p WHERE p.age IN ?1 AND p.job IN  ?2 ");

query.setParameter(1, ageList);
query.setParameter(2, jobList);

Here I am using a SELECT subquery. In fact if I use this query,

DELETE.... Where pr.person.age IN ?1

Hibernate will not accept it and throw an exception.

Problem:

The problem with the first query is that when ageList or the jobList is null, nothing will be returned. So we should put the parameter only if it is not null. We can so create a StringBuilder and put the first part of the request and according to what parameter we have, we create the rest of the query.

Solution: 

But a more safe think to do is to use the Criteria Builder in order to select the rows to delete, then delete the rows using entityManager.remove(entity). This is also very useful if we need to do a Cascade DELETE.

So the first think is to do like this:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery query = builder.createQuery(PersonRecord.class);
Root root = query.from(PersonRecord.class);

List predicateList = new ArrayList();

if(ageList != null && !ageList .isEmpty()){
predicateList.add(builder.isTrue(root.get("person").get("age").in(ageList )));
}
if(jobList!= null && !jobList.isEmpty()){
predicateList.add(builder.isTrue(modelTypeRoot.get("person").get("job").in(jobList)));
}

query.where(builder.and(predicateList.toArray(new Predicate[predicateList.size()])));

List personToDelete= entityManager.createQuery(query).getResultList();

for(PersonRecord item:personToDelete){
       // Make the entity attached again
entityManager.merge(item);
      // Here a CASCADE remove will be done easily
entityManager.remove(item);
}

This is only a temporarely solution till we will get the JBoss EAP with JPA 2.1




Monday, March 24, 2014

JPQL Select the Latest record date for each User and Correct Use of LEFT OUTER JOIN

Using JPQL to write a complex query, I was checking for the latest record added for each user.
In fact, let's say that the user borrow books form library and we want to know the latest book taken for each user.


My SQL request should be like this :

select user_id, user_name, mobile_phone, g.group_name,  borrowing_date
from books_record b 
inner join user u on b.user_id = u.user_id
left outer join group g on b.group_id = g.group_id
where (user_id, borrowing_time) in (
    select br.user_id, max(br.borrowing_time)
    from books_record br
    group by br.user_id
)

I am using a LEFT OUTER JOIN as reference on group can be NULL.

Using criteria builder, I wasn't able to generate this query, as I didn't now how to put two columns for the IN.

query.where(builder.in(root.get("user").get("userId"), root.get("borrowingTime")).value(subQuery));

So I have decided to use JPQL, where I construct a new bean in the result by giving my columns.


So the JPQL query shoul look like this (I declared it as a NamedQuery) :

  SELECT new org.project.test.MyPerson(b.user.personId, b.user.userName, b.user.mobilePhone, g.groupName)
  FROM BooksRecord b 
  LEFT OUTER JOIN b.group g
  WHERE ( b.user.userId,  b.borrowingTime)
  IN (

SELECT mxb.user.userId, MAX(mxb.borrowingTime)
FROM BooksRecord mxb
GROUP BY mxb.user.userId

)

JPA Hibernate CriteriaBuilder, Order the returned rows, Limit Result and construct a new Bean in the result with Left Join

Using Criteria Builder, we need sometime to Order the result, and even to Limit the size of the returned rows. We need also to Create a new bean directly in the query with or without a LEFT JOIN. The join in used if the attribute (which is a foreign key) may be null.



To the above mentioned requirement using JPA criterai builder, the code is:

 CriteriaBuilder builder = entityManager.getCriteriaBuilder();
 CriteriaQuery query = builder.createQuery(MyPerson.class);
 Root root = query.from(Person.class);

query.select(builder.construct(MyPerson.class, 
root .get("personName"),
root .get("phone").get("mobilePhone"),
root .join("address", JoinType.LEFT).get("country"),
        root.get("age"),
));

query.orderBy(builder.desc(root.get("age")));

alerts = entityManager.createQuery(query).setMaxResults(MAX_RESULT).getResultList();

That's all, hope it helps you.

Hibernate JPA Resolve Error Unable to resolve attribute [phone] against path

Working with JPA, I have an entity called Person which have reference on another entity called Phone.
In order to get the MobilePhone, I do :

root.join("phone", JoinType.LEFT).get("mobilePhone"),
OR
root.get("phone").get("mobilePhone"),

Doind this, I got an error :
Unable to resolve attribute [status] against path.

After some investigation, I have found that I have changed the name of my attribute in my code, from personPhone to phone, but the getter and setter still with the old name.
So to get my code working, I should use the same attribute name in  the getter also :

Person{

    Phone phone;
    ...
   Phone getPhone{
             return phone;
   }
}

Saturday, March 22, 2014

Jpa Hibernate insert Query: Error in named query: insertQuery: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: VALUES

In order to insert a record into the database, I was wondering to use SQL insert in order to entityManager.persist, as I would like to provide directly the foreign keys.
So I was using a Named Query.
@NamedQuery(name="insertQuery",
query="INSERT INTO person (person_id, name) VALUES (:person_id, :name)")

But at compilation time , I got this error:

 Error in named query: insertQuery: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: VALUES 

In fact, the solution is to use a Native Query.

So I needed to change the @NamedQuery into @NamedNativeQuery. 

As I should setParameters, I should use the createNamedParameter. Otherwise, I will have the error :
 could not locate named parameter.
So my query should look like this.

Query query = entityManager.createNamedQuery("insertQuery")
query.setParameter("person_id", person.getId()); 

Wednesday, March 19, 2014

Hibernate JPA Change the implicit INNER JOIN with a LEFT JOIN with Criteria Builder and build a new Result bean: Only one LEFT JOIN Query is generated

Here my experience with the Generated Queries using my lovely Hibernate. I was stuck for about four days with one of the generated query, but finally I find the solution.





I was developing a code in order to get Persons from my tables using JPA (Hibernate implementation) and Criteria Builder . Performing the test, I have noticed that Hibernates returns only Persons which have a Phone number (as I have a foreign Key on a Contact table). Hibernate do by default an INNER JOIN, and not a LEFT JOIN.

SO to force Hibernate doing a LEFT JOIN with the criteria Builder (I was creating a dynamic query), I used this code:

Root root = query.from(Person.class);

Join phone = root.join("contact", JoinType.LEFT);
...
query.select(builder.construct(MyPerson.class, 
               root.get("contact").get("phone")

The generated Query where :

SELECT phone2.number, person1.name
FROM person person1
LEFT OUTER JOIN phones phone1 ON person1.contact_id = phone1.id
,phones phone2
WHERE 
person1.contact_id = phone2.id

So Hibernate IGNORES in fact my Left JOIN even if it put it in the query. It use the Phone2 and not Phone1 present in the Left Join.  So the rows with contact null, is not yet returned.

If I build my bean by giving the root only, it will generate many other requests.
query.select(builder.construct(MyPerson.class, root);

It was very hard to finally find the solution which consists of removing the Join and do the join while creating the new bean. So the code should be in fact like this:

Root root = query.from(Person.class);
query.select(builder.construct(MyPerson.class, 
   root.join("contact", JoinType.LEFT).get("phone"),...));

So finally the generated query is exactly what I wanted:

SELECT phone1.number, person1.name
FROM person person1
LEFT OUTER JOIN phones phone1 ON person1.contact_id = phone1.id


Tuesday, March 18, 2014

Resolve JPA Criteria Builder org.hibernate.QueryException: could not instantiate class from tuple

Using Criteria Builder in JPA, I construct a bean from the query result using this line:

query.select(builder.construct(MyNewBean.class, root));

I give here the root and not root.get("colName"), as I have difficulties in generating queries as I like. I will speak about that later. But now let us focus on the first problem.

While testing my code, I get

org.hibernate.QueryException: could not instantiate class className from tuple
at org.hibernate.transform.AliasToBeanConstructorResultTransformer.transformTuple
I have thought first that I shouldn't give root (as I was used to give root.get("user").get("name"), root.get("phone")). But the problems wasn't really that.
Just after reading again the error, I have found this :
Caused by: java.lang.NullPointerException

OK. The Problem is in my constructor. I do
this.userName = MyEntity.get("user").get("name");

In fact, User refers to  another entity, so when we get the user, it can be NULL. Which will generate the nullPointerException and thus the tuple Error. So before getting the entities attributes make sure that they are not null (No need to check that for the NOT NULL foreign Keys)

if( MyEntity.get("user") != null){
   this.userName = MyEntity.get("user").get("name");
}

An advice is to use also an EAGER fetch if you are sure that you need the parameters (to return to a Web Service Client). So, only one request will be generated. If you use a Lazy join, at every call to get, a new Select will be done which will degrade performance.

Tuesday, March 11, 2014

Resolved : Set the Database Default Value in a Hibernate/JPA Save Persist

Using JPA (with Hibernate), I was inserting a record in my database. In my table, one column is defined with a DEFAULT Value.
But when I insert a save, persist my record, JPA put it as NULL.
So using JPA, the solution was to use insertable = false in the column definition. JPA will ignore then that column while inserting in the Database and the default value will be used.

@Column(name = "myColumn", length = 35, insertable = false)

Sunday, March 9, 2014

Resolve Error: ERROR: syntax error at or near "cross"

When I was testing my application, I have encountered an error using such a query:

@NamedQuery(name = "entity.myquery", 
query = "UPDATE MyEntity d SET d.isEnabled=false where d.myTest.id = :testId")

I get this error :

org.hibernate.exception.SQLGrammarException,
ERROR: syntax error at or near "cross"


Using this query, Hibernate translate it to a join query.

update mySchema.my_entity cross join  set is_enabled = false where id = ?

Or, no join is accepted in a Bulk HQL query.
So the Solution is to use a sub-select.

@NamedQuery(name = "entity.myquery", 
query = "UPDATE MyEntityd SET d.isEnabled=false where d.myTest.id IN "
+ "(SELECT e.id FROM myTest e where id = :testId)")


Tuesday, March 4, 2014

Resolve org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager' is defined

When testing my application, an error appear :

 org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager' is defined

In fact, in the ApplicationContext, I am defining the transaction manager with another name:
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">

So, as Spring is checking for the default name, I just put it in my configuration.
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">

I have seen that it is possible to use another name, nut you should sepcify it in the @Transactional annotation:
@Transactional(value="myTxManager")

Now it is working ;)

Monday, March 3, 2014

Resolved: Entity Manager cannot persist entities in database

I was developing a DAO layer using JPA specification (with JTA transaction managed by  Spring). When I tried to insert a new entity. I was using a shared entity manager and managing my transaction like this.

@PersistenceContext
private EntityManager entityManager;


entityManager.getTransaction().begin();

.....
entityManager.getTransaction().commit(); 

Once tested, I had this error:
 java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:220) [spring-orm-4.0.1.RELEASE.jar:4.0.1.RELEASE]
at $Proxy82.getTransaction(Unknown Source)

So I should use Spring Transactions. I had thus added @Transaction annotation to my method, and removed the getTransaction..  I also added flush in order to "commit" the work.

entityManager.persist(item);
entityManager.flush(); 

But it didn't work and I have this error in  my log.
entitymanager persist no transaction is in progress

So I think my @Transaction annotations are not taken into consideration and thus transactions are not initialized.
So in order to solve this problem I have added this line in my applicationContext
< tx:annotation-driven/>

(as I am using jndi entitymanagerfactory lookup, I have this :
<tx:jta-transaction-manager/>)

The problem is so resolved :)

Tuesday, February 25, 2014

Resolve Error: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet

Working in a JPA project, I had this error:

javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
....
Caused by: org.postgresql.util.PSQLException: ERROR: relation .. does not exist

This error can appear if you are working with two schema in your database. If you are declaring a persistence.xml with only one persistence-unit, there will be an ambiguity as Hibernate will not know the schema on which you are working.
So to resolve this, one possible solution is to add schema name in you entity.

@Entity
@Table(name = "my_table", schema="schema_one")
public class MyTable implements java.io.Serializable

Resolve a org.hibernate.HibernateException: Wrong column type in Error

While generating Entities, some problems can occur.  In fact in some Entities, I had this error:

org.hibernate.HibernateException: Wrong column type Found: int2, expected: int4

In my database, I was using smallint. But when the entities were generated, the attrbute type was set to Integer.

As I need smallint type in my database, the solution was to modify the attribute type to short.

This is sufficient to resolve the problem.

Resolve [Classpath]: Could not create JPA based Configuration and Invalid persistence xml Errors in Eclipse JBoss eap 6.2

The problem is that when I have created the persistence.xml, I was using JPA2.1. JBoss Eap 6.2 comes with JPA2.0, I am also using JBoss Tools. So I have two problems

by: javax.persistence.PersistenceException: Invalid persistence.xml.
Error parsing XML (line-1 : column -1): cvc-elt.1: Cannot find the declaration of element 'persistence'.

and 

[Classpath]: Could not create JPA based Configuration






Solution:  You should not use JPA2.1 but instead use JPA 2.0 as JBoss comes with this latest version. So in the persistence.xml use this declaration.

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"

Now my persistence.xml is working and I can see my tables in the Hibernate View.


And Here my Hibernate console:

Don't forget to specify the Database connection with the right JDBC. after this, you can see your tables. And thus generate your entities.

Right clic on the project --> JPA tools --> Generate Entities from Tables, and Specify the Hibernate Console.


The entities will be correctly generated.


Monday, February 24, 2014

Resolved Error: org.hibernate.MappingException: Repeated column in mapping for entity

When creating a JPA project, I have created my entities using eclipse and Hibernate tools, See this link.When deploying my application on JBoss server, I had this error:

 org.hibernate.MappingException: Repeated column in mapping for entity: org.qmic.mdd.enterprise.model.MddRelationTableOneTableTwo column: person_id (should be mapped with insert="false" update="false")
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:696)
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:718)
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:740)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:493)
at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1324)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1786)
at org.hibernate.ejb.EntityManagerFactoryImpl.(EntityManagerFactoryImpl.java:96)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:914)


In fact, in some association table I use a Composite Primary Key. As the association table should only use these keys, the association with these keys should be set to insert=false and update=false. It is not of the relation class to modify these attributes.

@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="person_id", insertable=false, updatable=false)

So adding these properties, the problem is resolved.


Thursday, February 20, 2014

JBoss EAP 6 Persistence unit problem: Jboss specify the unitName for each reference to a persistence unit

When depolying my application on JBoss EAP 6.2, I had this error:

"
 Persistence unitName was not specified and there are 2 persistence unit definitions in application deployment deployment "myapp.war".  Either change the application deployment to have only one persistence unit definition or specify the unitName for each reference to a persistence unit.
"
My application uses JPA 2.1 with Hibernate implementation 4.3. My persistence.xml contains two persistence-unit, one per DB schema. See my JPA example.



NB: with Hibernate 4.3, the provider is org.hibernate.jpa.HibernatePersistenceProvider.
JBoss (eap 6.x, as 7.x) it implicitly load some modules. JPA will also be loaded by JBoss as it detects the persistence.xml. According to the dosumentation :

"During application deployment, JPA use is detected (e.g. persistence.xml or @PersistenceContext/Unit annotations) and injects Hibernate dependencies into the application deployment. This makes it easy to deploy JPA applications."


JBoss eap 6.2 comes also with JPA 2.0 and Hibernate 4.2.7. More details about the module version is avialable in this RedHat Link


In order to remove this error while deploying, and as I provide the required libs. I have edited the standalone.xml (Shutdown JBoss first) by removing the JPA subsystem subsystem xmlns="urn:jboss:domain:jpa:1.1".




When starting JBoss, this subsytem definition will be removed even from standalone.xml.

Now my application is deploying on JBoss.

Mmmmm I have found a better think. In fact, as I am defining two persistence-unit, every time that I use @PersistenceUnit or @PersistenceContext, I should specify the unitName, otherwhise the created entityManager will not know on which persistenceUnit it is working.
After a search in all my classes, I have found that really I have forgot to mention that. So I have restored the JPA subsystem in JBoss (standalone.xml). Now everytime that I use @Persistencexxx, I specify the  unitName.

@PersistenceContext(unitName="my_first_persitence_unit") 
@PersistenceUnit(unitName="my_second_persitence_unit") 





Articles les plus consultés