it-roy-ru.com

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)?

19
Menno

Вы можете попробовать один из следующих способов:

  • С помощью метод createNativeQuery(sqlString, resultClass)

    Собственные запросы также можно определять динамически с помощью API EntityManager.createNativeQuery().

    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 Или XML-элемент <named-native-query>.

    @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 ).

───────
NOTE: Что касается использования getSingleResult(), см. Почему вы никогда не должны использовать getSingleResult() в JPA .

45
Paul Vargas

Пожалуйста, обратитесь 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);
2
Darshan Patel

Принятый ответ неверен.

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 кажется единственным способом избавиться от предупреждения. Лично я предпочитаю подавлять предупреждение, так как считаю это недостатком библиотеки, а не тем, о чем мне следует беспокоиться.

0
Derek White