Total Pageviews

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

2015/02/02

Generating entities from tables in Eclipse


Using this following procedure to generate Java persistent entities from database tables. 

1.  File => New => JPA Project => Click Next

2. Assign Project Name => Click Next


3. Click Next


4. Assign Platform and configure database connection => Click Finish


5. The sample JPA project, JPA_Project, had been created


6. Click src => Right Click => New => JPA Entities from Tables


7. Checked the tables which you would like to generate entities => Click Next


8. Click Next


9. Assign package name where your entities would like to place => Click Next


10. Click Finish


11. Check Result


 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package gov.nta.entity.fms;

import java.io.Serializable;
import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;

/**
 * The persistent class for the FMS406FF database table.
 * 
 */
@Entity
@NamedQuery(name = "Fms406ff.findAll", query = "SELECT f FROM Fms406ff f")
public class Fms406ff implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "YYY_MM")
    private String yyyMm;

    @Column(name = "REMARKS1")
    private String remarks1;

    @Column(name = "REMARKS2")
    private String remarks2;

    @Column(name = "REMARKS3")
    private String remarks3;

    @Column(name = "UPDATE_DATE")
    private Timestamp updateDate;

    @Column(name = "USER_ID")
    private String userId;

    public Fms406ff() {
    }

    public String getYyyMm() {
        return this.yyyMm;
    }

    public void setYyyMm(String yyyMm) {
        this.yyyMm = yyyMm;
    }

    public String getRemarks1() {
        return this.remarks1;
    }

    public void setRemarks1(String remarks1) {
        this.remarks1 = remarks1;
    }

    public String getRemarks2() {
        return this.remarks2;
    }

    public void setRemarks2(String remarks2) {
        this.remarks2 = remarks2;
    }

    public String getRemarks3() {
        return this.remarks3;
    }

    public void setRemarks3(String remarks3) {
        this.remarks3 = remarks3;
    }

    public Timestamp getUpdateDate() {
        return this.updateDate;
    }

    public void setUpdateDate(Timestamp updateDate) {
        this.updateDate = updateDate;
    }

    public String getUserId() {
        return this.userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

}

2014/08/27

ORA-17004 : Invalid Column Type

Problem
I am using JPA(Java Persistence API) as my persistence tier technology to write data into Oracle database. Here is the database schema for the targeted table:
Column
Type
Size
Nulls
Default
Comments
EXE_ID
number
20
執行ID, Calendar.getInstance().getTimeInMillis()
FUNCTION_ID
varchar2
20
功能代號
MESSAGE
nvarchar2
2000
 V 
null
執行訊息
EXECUTE_TYPE
varchar2
1
V
null
C:CRON JOB, M: MANNUAL, U:Upload
USER_ID
varchar2
20
 V 
null
批次執行時,帶功能名稱,手動執行時,帶執行人USER_ID
UPDATE_DATE_TIME
timestamp(6)
11,6
 V 
now
執行時間
FILE_NAME
varchar2
40
 V 
null
檔案名稱

Here is the code snippet:
1:    public void writeLog(Boolean isSuccessful, String funId, String exceptionMsg) {  
2:      try {  
3:        StringBuilder sql = new StringBuilder();  
4:        sql.append("INSERT INTO FMS900FA(EXE_ID, FUNCTION_ID, MESSAGE, EXECUTE_TYPE, USER_ID, FILE_NAME)");  
5:        sql.append(" VALUES(:EXE_ID, :FUNCTION_ID, :MESSAGE, :EXECUTE_TYPE, :USER_ID, :FILE_NAME)");  
6:        Map<String, Object> params = new HashMap<String, Object>();  
7:        params.put("EXE_ID", BigInteger.valueOf(Calendar.getInstance().getTimeInMillis()));  
8:        params.put("FUNCTION_ID", funId);  
9:        if (isSuccessful) {  
10:          params.put("MESSAGE", "執行成功");  
11:        } else {  
12:          params.put("MESSAGE", exceptionMsg);  
13:        }  
14:        params.put("EXECUTE_TYPE", "C");  
15:        params.put("USER_ID", "ADMIN");  
16:        params.put("FILE_NAME", "NA");  
17:        sqlExecutor.insert(sql, params);  
18:      } catch(Exception e) {  
19:        throw e;  
20:      }  
21:    }   

But program throw SQLException
1:  Caused by: org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [INSERT INTO FMS900FA(EXE_ID, FUNCTION_ID, MESSAGE, EXECUTE_TYPE, USER_ID, FILE_NAME)  VALUES(?, ?, ?, ?, ?, ?) ]; SQL state [99999]; error code [17004]; invalid column type; nested exception is java.sql.SQLException: invalid column type  
2:       at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
3:       at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
4:       at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
5:       at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:660) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
6:       at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:909) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
7:       at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:933) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
8:       at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:313) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
9:       at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:318) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
10:       at com.cht.commons.persistence.query.SqlExecutor.execute(SqlExecutor.java:97) ~[cht-commons-persistence-0.1.0-SNAPSHOT.jar!/:0.1.0-SNAPSHOT]  
11:       at com.cht.commons.persistence.query.SqlExecutor.insert(SqlExecutor.java:157) ~[cht-commons-persistence-0.1.0-SNAPSHOT.jar!/:0.1.0-SNAPSHOT]  
12:       at com.cht.commons.persistence.query.SqlExecutor.insert(SqlExecutor.java:146) ~[cht-commons-persistence-0.1.0-SNAPSHOT.jar!/:0.1.0-SNAPSHOT]  
13:       at gov.nta.fms.service.FmsBatchLog.writeLog(FmsBatchLog.java:139) ~[fms-service-1.0.0-SNAPSHOT.jar:1.0.0-SNAPSHOT]  
14:       at gov.nta.fms.service.Fms435xService.initFms435fa(Fms435xService.java:228) ~[fms-service-1.0.0-SNAPSHOT.jar:1.0.0-SNAPSHOT]  
15:       at gov.nta.fms.service.Fms435xService$$FastClassBySpringCGLIB$$75f6a95.invoke() ~[na:na]  
16:       at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
17:       at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711) ~[spring-aop-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
18:       at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
19:       at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) ~[spring-tx-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
20:       at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262) ~[spring-tx-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
21:       at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) ~[spring-tx-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
22:       at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
23:       at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58) ~[spring-aop-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
24:       ... 111 common frames omitted  
25:  Caused by: java.sql.SQLException: invalid column type  
26:       at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8761) ~[na:na]  
27:       at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8259) ~[na:na]  
28:       at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:9012) ~[na:na]  
29:       at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8993) ~[na:na]  
30:       at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:230) ~[na:na]  
31:       at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.setObject(WrappedPreparedStatement.java:986) ~[na:na]  
32:       at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:402) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
33:       at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:235) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
34:       at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:150) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
35:       at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.setValues(PreparedStatementCreatorFactory.java:300) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
36:       at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:252) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
37:       at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:638) ~[spring-jdbc-4.0.3.RELEASE.jar!/:4.0.3.RELEASE]  
38:       ... 129 common frames omitted  

How to solve it?
This SQLException, ORA-17004 : Invalid Column Type, results from EXE_ID this column.

We use BigInteger originally, but fail to do insert. As we change to use BigDecimal, it's working fine now. But the root cause is still unknown.
1:    public void writeLog(Boolean isSuccessful, String funId, String exceptionMsg) {  
2:      try {  
3:        StringBuilder sql = new StringBuilder();  
4:        sql.append("INSERT INTO FMS900FA(EXE_ID, FUNCTION_ID, MESSAGE, EXECUTE_TYPE, USER_ID, FILE_NAME)");  
5:        sql.append(" VALUES(:EXE_ID, :FUNCTION_ID, :MESSAGE, :EXECUTE_TYPE, :USER_ID, :FILE_NAME)");  
6:        Map<String, Object> params = new HashMap<String, Object>();  
7:        params.put("EXE_ID", new BigDecimal(Calendar.getInstance().getTimeInMillis()));  
8:        params.put("FUNCTION_ID", funId);  
9:        if (isSuccessful) {  
10:          params.put("MESSAGE", "執行成功");  
11:        } else {  
12:          params.put("MESSAGE", exceptionMsg);  
13:        }  
14:        params.put("EXECUTE_TYPE", "C");  
15:        params.put("USER_ID", "ADMIN");  
16:        params.put("FILE_NAME", "NA");  
17:        sqlExecutor.insert(sql, params);  
18:      } catch(Exception e) {  
19:        throw e;  
20:      }  
21:  

2011/09/09

JPA Annotation @JoinColumn / @JoinColumns 應用

Scenario
我們在利用JPA(Java Persistence API)的時候,code generator會自動幫table之間有關連的部份產生出來,但是在實際應用上,有可能table之間沒有關連性,但是卻需要來做join抓取資料的需求。


此時就要自行在該entity上宣告變數與join的欄位。若是single column的狀況下,可以採用@JoinColumn,若是composite column的話,可以採用@JoinColumns


Demo
NIGT001與NIGT007雖然沒有relationship,但是在實際應用上,常會做JOIN,彼此透過single column來做Join





在原本的NIGT001增加nigt007此attribute,並產生setter/getter methods,註明兩張table之間的relationship,name的部份是NIGT001的欄位,referencedColumnName的部份是NIGT007的欄位名稱,此二table彼此是透過上述欄位來進行join
 




NIGT001與NIGT022雖然沒有relationship,但是在實際應用上,常會做JOIN,彼此透過composite column來做Join





在原本的NIGT001增加nigt022此attribute,並產生setter/getter methods,註明兩張table之間的relationship,name的部份是NIGT001的欄位,referencedColumnName的部份是NIGT022的欄位名稱,此二table彼此是透過上述欄位來進行join




2011/08/12

The name "Ybdt010" is not a recognized entity or identifier

Problem
As I do query via OpenJPA in WAS(WebSphere Application Server), it complains this error message
 org.apache.openjpa.persistence.ArgumentException: An error occurred while parsing the query filter "select t from Ybdt010 t where t.emplCd = ?1". Error message: The name "Ybdt010" is not a recognized entity or identifier. Perhaps you meant Nigt010, which is a close match. Known entity names: [Nigw001, Nigt010, Nigt055, Nigt011, Nigt012, JUTSysParam, Nigt013, Nigt036, Nigt037, Nigt038, Nigt039, JUTMsg, Nigt080, Nigt081, Nigt082, Nigt040, Nigt063, Nigt041, Nigt042, Nigt020, Nigt064, Nigt021, Nigt043, Nigt044, Nigt088, Nigt001, Nigt045, Nigt005, Nigt006, Nigt007, Nigt008, JUTCode]   
 at org.apache.openjpa.kernel.exps.AbstractExpressionBuilder.parseException(AbstractExpressionBuilder.java:118) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
 at org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getClassMetaData(JPQLExpressionBuilder.java:177) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
 at org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.resolveClassMetaData(JPQLExpressionBuilder.java:150) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
 at org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getCandidateMetaData(JPQLExpressionBuilder.java:225) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
 at org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getCandidateMetaData(JPQLExpressionBuilder.java:195) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   


Why it happened?
There was a problem if the first time you accessed an Entity type (ie. Ybdt010) via a Query instead of some other access.
It should be WebSphere's bug, need to install fixpack to fix this problem.

Solution
Here has a workaround solution to fix this problem. Before executing your query, you just insert something simple like...
 Ybdt010 ybdt010 = new Ybdt010();  


2011/08/08

org.apache.openjpa.persistence.NoResultException


Problem
As we do search via primary key, it will show this exception message if JPA does not search any matched data
1:  org.apache.openjpa.persistence.NoResultException: The query on candidate type "class gov.fdc.nig.domain.Nigt020" with filter "select t1 from Nigt020 t1, Nigt022 t2 where t2.id.dlvUnit = ?1 and t2.id.taxCd = ?2 and t2.id.dlvYr = ?3 and t2.id.flgTp = ?4 and t2.id.serialNo = ?5 and t2.paraTp <> ?6 and t2.paraTp = t1.paraTp" was configured to have a unique result, but no instance matched the query.   
2:  at org.apache.openjpa.kernel.QueryImpl.singleResult(QueryImpl.java:1299) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
3:  at org.apache.openjpa.kernel.QueryImpl.toResult(QueryImpl.java:1221) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
4:  at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:990) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
5:  at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:805) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
6:  at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:775) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
7:  at org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:533) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
8:  at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:252) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   
9:  at org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.java:317) ~[com.ibm.ws.jpa.jar:1.0.1-SNAPSHOT]   


The original approach is to call getSingleResult method:
1:  public Object createQueryForSingleResult(String jpql, Object[] params, Dao.PersistenceUnit persistenceUnitName) {   
2:       EntityManager em = getEntityManager(persistenceUnitName);   
3:       Query query = em.createQuery(jpql);   
4:       for (int i = 0; i &lt; params.length; i++) {   
5:            query.setParameter(i + 1, params[i]);   
6:       }   
7:       return query.getSingleResult();   
8:  }  

Solution
Just change to this way, then the exception will not take place again:
1:  public Object createQueryForSingleResult(String jpql, Object[] params, Dao.PersistenceUnit persistenceUnitName) {   
2:       Object result = null;   
3:       EntityManager em = getEntityManager(persistenceUnitName);   
4:       Query query = em.createQuery(jpql);   
5:       for (int i = 0; i < params.length; i++) {   
6:            query.setParameter(i + 1, params[i]);   
7:       }   
8:       List list = query.getResultList();   
9:       if(!CollectionUtils.isEmpty(list)){   
10:            result = list.get(0);   
11:       }   
12:       return result;   
13:  }   

2011/07/28

Handling JPA lifecycle event using listeners and callbacks

Problem
As we manipulate table, we need to insert values into user id(使用者代號), timestamp(西元年) and update date(民國年) as we do insert or update.
It's prone to forget to insert values to these columns.

Solution
Define setting value method and utilize JPA lifecyle to invoked automatically by JPA when these events occur.

JPA Lifecycle Events
Callback methods are user defined methods that are attached to entity lifecycle events and are invoked automatically by JPA when these events occur.

Internal callback methods should always return void and take no arguments. They can have any name and any access level (public, protected, package and private) but should not be static.

The annotation specifies when the callback method is invoked:
  • @PrePersist - before a new entity is persisted (added to the EntityManager).
  • @PostPersist - after storing a new entity in the database (during commit or flush).
  • @PostLoad - after an entity has been retrieved from the database.
  • @PreUpdate - when an entity is identified as modified by the EntityManager.
  • @PostUpdate - after updating an entity in the database (during commit or flush).
  • @PreRemove - when an entity is marked for removal in the EntityManager.
  • @PostRemove - after deleting an entity from the database (during commit or flush).

Implementation Restrictions
To avoid conflicts with the original database operation that fires the entity lifecycle event (which is still in progress) callback methods should not call EntityMan­ager or Query methods and should not access any other entity objects.

If a callback method throws an exception within an active transaction, the transaction is marked for rollback and no more callback methods are invoked for that operation.

How to do it
1. Define EntityListener class
 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package gov.fdc.nig.domain.listener;

import gov.fdc.common.util.DateUtil;
import gov.fdc.nig.util.NigUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Calendar;

import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;

public class EntityListener {

 /**
  * Set date time and user id
  *
  * This method will be invoke before a new entity is persisted or
  * when an entity is identified as modified by the EntityManager
  *
  * @param obj Object
  * @throws IllegalArgumentException
  * @throws IllegalAccessException
  * @throws InvocationTargetException
  */
 @SuppressWarnings("unused")
 @PrePersist
 @PreUpdate
 private void setTimeAndUser(Object obj) throws IllegalArgumentException,
  IllegalAccessException, InvocationTargetException {
   Method methods[] = obj.getClass().getDeclaredMethods();
   String methodName = "";
   for (Method method: methods) {
    methodName = method.getName();
    if (methodName.matches("setUpdateDate")) {
     method.invoke(obj, DateUtil.getFormattedDate(NigUtils.getCurrentTimestamp(), "twyMMdd"));
    } else if (methodName.matches("setTimeStamp")) {
     method.invoke(obj, new Timestamp(Calendar.getInstance().getTime().getTime()));
    } else if (methodName.matches("setUserId")) {
     method.invoke(obj, NigUtils.getUser().getUserID());
    } else if (methodName.matches("setUpdateUserCd")) {
     method.invoke(obj, NigUtils.getUser().getUserID());
    }
   }
  }
}


2. add @EntityListeners({EntityListener.class}) annotation to each entity class

1
2
3
4
5
6
7
8
9
package gov.fdc.nig.domain;
@Entity
@EntityListeners({
 EntityListener.class
})
@Table(name = "NIGT036", schema = "AP_TAX")
public class Nigt036 extends DomainBase {
 //............
}

Therefore, we don't need to set these columns in controller class. And we won't forget to set values to theses columns again.

2011/07/21

Wrapping JPQL Query Results with Instances of Custom Result Classes

JPA supports wrapping JPQL query results with instances of custom result classes. This is mainly useful for queries with multiple SELECT expressions, where custom result objects can provide an object oriented alternative to representing results as Object[] or Object elements.

The fully qualified name of the result class is specified in a NEW expression, as follows:
1
2
3
4
5
6
7
8
   StringBuilder sql = new StringBuilder();
   sql.append(" select new gov.fdc.nig.bean.NIG451Bean(t1.manageCd, t1.baTaxMk, ");
   sql.append(" t1.vioHostNm, t1.vioHostIdnBan, t1.vioYr, t1.addrHsnNm, ");
   sql.append(" t1.addrTownNm, t1.addrVillNm, t1.addrLin, t1.addrRoadNo, ");
   sql.append(" t1.respNm, t1.respIdn, t1.prstAdtrCd, t1.nigt007.adtrNm, ");
   sql.append(" t1.authMk, t1.adtSgstMk) from Nigt001 t1");
   sql.append(" where t1.id.dlvUnit = ?1 and t1.id.taxCd = ?2 and t1.id.dlvYr = ?3 ");
   sql.append(" and t1.id.flgTp = ?4 and t1.id.serialNo = ?5 ");


The result class must have a compatible constructor that matches the SELECT result expressions, as follows:
 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
   public class NIG451Bean extends BeanBase {
       // 管理代號
       private String manageCd;
       // 本稅註記
       private String baTaxMk;
       // 違章主體名稱
       private String vioHostNm;
       // 違章主體統一編號
       private String vioHostIdnBan;
       // 違章年度
       private String vioYr;
       // 地址縣市名稱
       private String addrHsnNm;
       // 地址鄉鎮市區名稱
       private String addrTownNm;
       // 地址村里名稱
       private String addrVillNm;
       // 地址鄰
       private String addrLin;
       // 地址街道門牌
       private String addrRoadNo;
       // 負責人姓名
       private String respNm;
       // 負責人身分證統一編號
       private String respIdn;
       // 目前審理人員代號
       private String prstAdtrCd;
       // 審理人員姓名
       private String adtrNm;
       // 授權註記
       private String authMk;
       // 審查意見補頁註記
       private String adtSgstMk;
       
       public NIG451Bean(String manageCd, String baTaxMk, String vioHostNm,
                         String vioHostIdnBan, String vioYr, String addrHsnNm,
                         String addrTownNm, String addrVillNm, String addrLin,
                         String addrRoadNo, String respNm, String respIdn,
                         String prstAdtrCd, String adtrNm, String authMk, String adtSgstMk) {
           super();
           this.manageCd = manageCd;
           this.baTaxMk = baTaxMk;
           this.vioHostNm = vioHostNm;
           this.vioHostIdnBan = vioHostIdnBan;
           this.vioYr = vioYr;
           this.addrHsnNm = addrHsnNm;
           this.addrTownNm = addrTownNm;
           this.addrVillNm = addrVillNm;
           this.addrLin = addrLin;
           this.addrRoadNo = addrRoadNo;
           this.respNm = respNm;
           this.respIdn = respIdn;
           this.prstAdtrCd = prstAdtrCd;
           this.adtrNm = adtrNm;
           this.authMk = authMk;
           this.adtSgstMk = adtSgstMk;
       }
       //setter and getter method
   }


The following code demonstrates running this query:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
   public NIG451Bean autoCompleteForNIG451(Nigt001PK nigt001pk) {
       StringBuilder sql = new StringBuilder();
       sql.append(" select new gov.fdc.nig.bean.NIG451Bean(t1.manageCd, t1.baTaxMk, ");
       sql.append(" t1.vioHostNm, t1.vioHostIdnBan, t1.vioYr, t1.addrHsnNm, ");
       sql.append(" t1.addrTownNm, t1.addrVillNm, t1.addrLin, t1.addrRoadNo, ");
       sql.append(" t1.respNm, t1.respIdn, t1.prstAdtrCd, t1.nigt007.adtrNm, ");
       sql.append(" t1.authMk, t1.adtSgstMk) from Nigt001 t1");
       sql.append(" where t1.id.dlvUnit = ?1 and t1.id.taxCd = ?2 and t1.id.dlvYr = ?3 ");
       sql.append(" and t1.id.flgTp = ?4 and t1.id.serialNo = ?5 ");
       
       EntityManager entityManager = getEntityManager_A05_TAX();
       Query query = entityManager.createQuery(sql.toString());
       query.setParameter(1, nigt001pk.getDlvUnit());
       query.setParameter(2, nigt001pk.getTaxCd());
       query.setParameter(3, nigt001pk.getDlvYr());
       query.setParameter(4, nigt001pk.getFlgTp());
       query.setParameter(5, nigt001pk.getSerialNo());
       
       return (NIG451Bean)query.getSingleResult();
   }


Any class with a compatible constructor can be used as a result class. It could be a JPA managed class (e.g. an entity class) but it could also be a lightweight 'transfer' class that is only used for collecting and processing query results.

If an entity class is used as a result class, the result entity objects are created in the NEW state, which means that they are not managed. Such entity objects are missing the JPA functionality of managed entity objects (e.g. transparent navigation and transparent update detection), but they are more lightweight, they are built faster and they consume less memory.