簡體   English   中英

JPA 本機查詢 select 並投射 object

[英]JPA Native Query select and cast object

我有一個 Object Admin擴展了User 默認情況下,這兩個對象都在我的 Derby 數據庫的表User_中(包括來自Admin的字段)。 通常我會 select 這樣的User

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root user= query.from(User.class);
Predicate predicateId = cb.equal(category.get("id"), id);
query.select(user).where(predicateId);
return em.createQuery(query).getSingleResult();

但是由於查詢的復雜性,我使用的是這樣的本機查詢:

Query query = em.createNativeQuery("SELECT USER.* FROM USER_ AS USER WHERE ID = ?");
query.setParameter(1, id);
return (User) query.getSingleResult();

盡管這會引發強制轉換異常。 我認為這是由於Admin中的任何字段造成的。

我的問題是,我如何 select 一個User使用與第一個示例相同結果的本機查詢(包括與 JPQL 查詢返回的相同值的@LOB@ManyToOne (等等))?

您可能想嘗試以下方法之一:

  • the method createNativeQuery(sqlString, resultClass)方法createNativeQuery(sqlString, resultClass)

    本機查詢也可以使用EntityManager.createNativeQuery() API 動態定義。

     String sql = "SELECT USER.* FROM USER_ AS USER WHERE ID = ?"; Query query = em.createNativeQuery(sql, User.class); query.setParameter(1, id); User user = (User) query.getSingleResult();
  • the annotation @NamedNativeQuery注解@NamedNativeQuery

    本機查詢是通過@NamedNativeQuery@NamedNativeQueries注釋或<named-native-query> XML 元素定義的。

     @NamedNativeQuery( name="complexQuery", query="SELECT USER.* FROM USER_ AS USER WHERE ID = ?", resultClass=User.class ) public class User { ... } Query query = em.createNamedQuery("complexQuery", User.class); query.setParameter(1, id); User user = (User) query.getSingleResult();

您可以在優秀的開放書Java PersistencePDF 格式)中閱讀更多內容。

────────
注意:關於getSingleResult() ,請參閱為什么你不應該在 JPA 中使用getSingleResult()

接受的答案是不正確的。

createNativeQuery將始終返回一個Query

public Query createNativeQuery(String sqlString, Class resultClass);

Query上調用getResultList返回List

List getResultList()

分配(或轉換)到List<MyEntity> ,會產生未經檢查的分配警告。

createQuery將返回一個TypedQuery

public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass);

TypedQuery上調用getResultList返回List<X>

List<X> getResultList();

這是正確輸入的,不會發出警告。

使用createNativeQuery ,使用ObjectMapper似乎是擺脫警告的唯一方法。 就我個人而言,我選擇取消警告,因為我認為這是庫中的一個缺陷,而不是我應該擔心的事情。

當您的本機查詢基於連接時,在這種情況下,您可以將結果作為對象列表獲取並進行處理。

一個簡單的例子。

@Autowired
EntityManager em;

    String nativeQuery = "select name,age from users where id=?";   
    Query query = em.createNativeQuery(nativeQuery);
    query.setParameter(1,id);

    List<Object[]> list = query.getResultList();

    for(Object[] q1 : list){

        String name = q1[0].toString();
        //..
        //do something more on 
     }

請參考JPA : How to convert a native query result set to POJO class collection

對於Postgres 9.4

List<String> list = em.createNativeQuery("select cast(row_to_json(u) as text) from myschema.USER_ u WHERE ID = ?")
                   .setParameter(1, id).getResultList();

User map = new ObjectMapper().readValue(list.get(0), User.class);

我找到的最佳解決方案是使用Interface projection

一開始,我創建了一個 DTO class 但它沒有用,用這樣的接口替換 class 效果很好:

@Query(value = "SELECT vat as vatRate, SUM(...) as amount from ...", nativeQuery = true)
List<VatReportLine> getSalesVats();


public interface VatReportLine {

    double getVatRate();

    long getAmount();
}

首先創建一個模型POJO

import javax.persistence.*;
@Entity
@Table(name = "sys_std_user")
public class StdUser {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "class_id")
    public int classId;
    @Column(name = "user_name")
    public String userName;
    //getter,setter
}

控制器

import com.example.demo.models.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import java.util.List;

@RestController
public class HomeController {
    @PersistenceUnit
    private EntityManagerFactory emf;

    @GetMapping("/")
    public List<StdUser> actionIndex() {
        EntityManager em = emf.createEntityManager(); // Without parameter
        List<StdUser> arr_cust = (List<StdUser>)em
                .createQuery("SELECT c FROM StdUser c")
                .getResultList();
        return arr_cust;
    }

    @GetMapping("/paramter")
    public List actionJoin() {
        int id = 3;
        String userName = "Suresh Shrestha";
        EntityManager em = emf.createEntityManager(); // With parameter
        List arr_cust = em
                .createQuery("SELECT c FROM StdUser c WHERE c.classId = :Id ANd c.userName = :UserName")
                .setParameter("Id",id)
                .setParameter("UserName",userName)
                .getResultList();
        return arr_cust;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM