Acewin
Acewin

Reputation: 1727

Working with entities for native SQL when not adding persistence.xml while using Spring + Hibernate JPA

Please consider the question closed. It seems my usecase does not have a solution while working with JPA 2.0. I had overlooked limitations of JPA 2.0 in this case. JPA 2.0 does not support a custom entity without using persistence.xml.

I am trying to test my application to work with Spring + Hibernate JPA while avoiding a dedicated persistence.xml. Working completely with annotation.

API I am using is Spring 4.3.3 and Hibernate JPA-2.0 on IBM WebSphere 8.0

I do not know of possible gaps for my usecase. It could be a simple miss on my part as well.

Objective is to execute native queries and map the result to a bean class. I am able to test my application with entities. JPA is able to validate mapping for them against actual database tables.

Why use native query and not write complete entity -> Queries involves multiple joins. DO not need to be include all the tables involved in the query as entity.

Part of the application context xml related to jpa looks like this

<bean id="jpaVendorApdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="databasePlatform" value="org.hibernate.dialect.DB2Dialect"></property>
    <property name="showSql" value="true" />
</bean>

<bean id="testEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="testDB2DataSource" />
  <property name="packagesToScan" value="com.app.dao" />
  <property name="jpaVendorAdapter">
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
  </property>
  <property name="jpaProperties">
     <props>
        <prop key="hibernate.hbm2ddl.auto">validate</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
     </props>
  </property>

Adding a simple example for my case The bean class for native query looks like below

public class OwnerDetails implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Id
    private String userInitials;

    private String teamCd;

    public String getUserInitials() {
        return userInitials;
    }

    public void setUserInitials(String userInitials) {
        this.userInitials= userInitials;
    }

    public String getTeamCd() {
        return teamCd;
    }

    public void setTeamCd(String teamCd) {
        this.teamCd= teamCd;
    }
}

with the query being

SELECT B.USER_INITS as userInitials, B.TEAM_CD as teamCd FROM APPTEAM A JOIN PQID B ON A.APP_OWNER_ID = B.SIGN_ON_ID WHERE A.APP_NAME = :appName

Code block to execute the native query

Query query = entityManager.createNativeQuery(queryString, className)(QUERY_STRING, OwnerDetails.class);
    query.setParameter("appName", "TESTAPP");


    OwnerDetails  result = (OwnerDetails ) query.getSingleResult();

I get below exception while trying to execute the query

Caused by: org.hibernate.MappingException: Unknown entity: com.app.dao.entity.OwnerDetails

I know this is because not including @Entity annotation But when I include the Entity annotation I get a different error

Caused by: org.hibernate.HibernateException: Missing table: OwnerDetails

......

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build EntityManagerFactory

I would like to know the missing link to setting up JPA while not using a persistence.xml

Update - as the API is JPA 2.0 Named Native Queries would not be supported

Upvotes: 0

Views: 1235

Answers (2)

Sai Ye Yan Naing Aye
Sai Ye Yan Naing Aye

Reputation: 6738

Try these steps.

  1. Put @Entity annotation in your class
  2. Put @Table annotation in your class

     @Entity
     @Table(name="YourTableName") //if you do not put name, the dafault value is your class name
     public class OwnerDetails implements Serializable {
     }
    
  3. Make sure your table is exist or not.

Edit:

If OwnerDetails is not entity and you are using JPA 2.1,then you can use SqlResultSetMapping with ConstructorResult.

Upvotes: 1

Khalil M
Khalil M

Reputation: 1858

If you are using JPA 2.1 version make sure you have these annoation:

@NamedNativeQuery (name = "some name"
query = "SELECT B.USER_INITS as userInitials, B.TEAM_CD as teamCd FROM APPTEAM A JOIN PQID B ON A.APP_OWNER_ID = B.SIGN_ON_ID WHERE A.APP_NAME = :appName"
resulSetMapping = "OwnerDetails") 

and:

@SqlResultSetMapping(name="some name", classes = {
    @ConstructorResult(targetClass = OwnerDetail.class, 
    columns = {@ColumnResult(name="userInitials"), @ColumnResult(name="teamCd")})
}) 

and later you just cast the result. But if you're using JPA version less than 2.1 that is not possible.

Upvotes: 0

Related Questions