JPA Собственный запрос выбора и приведения объекта
У меня есть объект Admin
который расширяется User
, По умолчанию оба объекта находятся в таблице. User_
моей базы данных Derby (включены поля из Admin
). Обычно я бы выбрал 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
,
У меня вопрос, как я могу выбрать User
используя собственный запрос с таким же результатом, как в первом примере (включая те же значения для @LOB
а также @ManyToOne
(и так далее), как будет возвращать запрос JPQL)?
6 ответов
Вы можете попробовать один из следующих способов:
Используя метод
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();
Использование аннотации
@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 Persistence (доступно в формате PDF).
───────
ПРИМЕЧАНИЕ: в отношении использования getSingleResult()
Посмотрите, почему вы никогда не должны использовать getSingleResult()
в JPA.
Принятый ответ неверен.
createNativeQuery
всегда будет возвращать Query
:
public Query createNativeQuery(String sqlString, Class resultClass);
призвание getResultList
на Query
возвращается List
:
List getResultList()
При назначении (или кастинге) List<MyEntity>
выдается предупреждение о непроверенном назначении.
В то время как, createQuery
вернет TypedQuery
:
public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass);
призвание getResultList
на TypedQuery
возвращается 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: Как преобразовать собственный набор результатов запроса в коллекцию классов POJO
За 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);
Лучшее решение, которое я нашел, — это использование проекции интерфейса .
Вначале я создал класс DTO, но он просто не работал, замена класса таким интерфейсом отлично работает:
@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;
}
}