Извлечение запроса JPQL как DTO в приложении Spring boot

#java #sql #spring #hibernate #jpql

#java #sql #весна #спящий режим #jpql

Вопрос:

В основном я пытаюсь выполнить запрос и поместить результат в объект класса Account . Что очень важно подчеркнуть, так это то, что запрос выполняет СОЕДИНЕНИЕ между 2 таблицами, КОТОРЫЕ НЕ ОТОБРАЖАЮТСЯ как @Entity . Итак, как я могу это сделать?

Это мой FooRepository.java класс

 @Repository
public interface FooRepository extends JpaRepository<Foo, Long> {

  Foo findById(Long id);

@Query(value = "SELECT Q1.ACCOUNT_NAME,"  
          "Q2.GROUP_NAME  "  
          "FROM USERS_DEV Q1n"  
          "JOIN USERS_GROUPS Q2 ON Q1.ACCOUNT_NAME = Q2.ACCOUNT_NAMEn"  
          "WHERE LOWER(Q1.ACCOUNT_NAME) = 'john.pit'", nativeQuery = true)
  List<Account> getAllAccounts();

  

Итак, как я могу изменить свой запрос, чтобы получить желаемый результат?

И вот моя учетная запись.класс java

 public class Account {

    String samAccountName;
    String groupName;

    public Account(String accountName, String groupName) {
        this.accountName = accountName;
        this.groupName = groupName;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }
}

  

Комментарии:

1. Избегайте использования nativeQuery , когда это возможно. Тем не менее, это должно сработать, если вы соответствующим образом сопоставите имена свойств (постоянный регистр больше не используется по умолчанию).

Ответ №1:

Вы можете использовать EntityManager и ResultTransformer :

 entityManager.createNativeQuery(
    "SELECT Q1.ACCOUNT_NAME,"  
    "Q2.GROUP_NAME  "  
    "FROM USERS_DEV Q1 "  
    "JOIN USERS_GROUPS Q2 ON Q1.ACCOUNT_NAME = Q2.ACCOUNT_NAME "  
    "WHERE LOWER(Q1.ACCOUNT_NAME) = 'john.pit'"
)
            .unwrap(NativeQuery.class)
            .setResultTransformer(new ResultTransformer() {
                @Override
                public Object transformTuple(Object[] tuple, String[] aliases) {
                    return new Account(
                        (String) tuple[0],
                        (String) tuple[1]
                    );
                }

                @Override
                public List transformList(List collection) {
                    return collection;
                }

            })
            .getResultList();
  

Может потребоваться приведение.

Комментарии:

1. Я сделал, как вы сказали, так что теперь я получаю это: InvalidDataAccessResourceUsageException: не удалось извлечь результирующий набор; SQL [n / a]; вложенным исключением является org.hibernate.exception. SQLGrammarException: не удалось извлечь результирующий набор, вызванный: java.sql.SQLSyntaxErrorException: ORA-00923: ключевое слово FROM не найдено там, где ожидалось

2. @MariusPop да, это моя ошибка, я думал, что это jpql. Для native должно быть другое решение, позвольте мне отредактировать свой ответ

3. @MariusPop попробуйте сейчас. Не беспокойтесь о том, что его устаревание ResultTransformer не будет удалено, пока не будет достойной замены

4. я не совсем знаком с EntityManager. Куда точнее я должен вставить этот код? Все еще в классе репозитория? Должен ли я создать экземпляр EntityManager?

5. @MariusPop Я предлагаю создать отдельный класс CustomFooRepository , там вы можете создать метод, который возвращает List<Account> и вставляет код. EntityManager может быть введен с помощью @Autowired

Ответ №2:

Может быть, я ошибаюсь, но я помню, что вы можете выполнить следующее (с помощью HQL):

 @Query("select new Account(u.name, g.groupName) "  
          "from User as u"  
          "join u.group as g"  
          "where LOWER(u.name) = 'john.pit'")

  

Синтаксис может быть неправильным, но я уверен, что вы можете использовать конструктор DTO в инструкции select, если используете HQL.

Надеюсь, это поможет вам: D

Комментарии:

1. это работает, только если таблицы отображаются как объекты

Ответ №3:

В качестве альтернативы вы можете использовать @NamedNativeQuery with @SqlResultSetMapping следующим образом:

 @Entity
@NamedNativeQuery(
  name = "findAllAccounts",
  query = 
     "SELECT "  
     "  Q1.ACCOUNT_NAME AS accountName, "  
     "  Q2.GROUP_NAME AS groupName "  
     "FROM USERS_DEV Q1 "  
     "JOIN USERS_GROUPS Q2 ON Q1.ACCOUNT_NAME = Q2.ACCOUNT_NAME "   
     "WHERE LOWER(Q1.ACCOUNT_NAME) = 'john.pit'",
  resultSetMapping = "findAllAccountsMapping"
)
@SqlResultSetMapping(
   name = "findAllAccountsMapping",
   classes = @ConstructorResult(
      targetClass = Account.class,
      columns = {
         @ColumnResult(name="accountName"),
         @ColumnResult(name="groupName"),
      }
   )
)
public class Foo {
   // ...
}
  

и FooRepository :

 @Repository
public interface FooRepository extends JpaRepository<Foo, Long> {

  @Query(name = "findAllAccounts", nativeQuery = true)
  List<Account> getAllAccounts();
}
  

Дополнительные сведения см. в документации по гибернации.

Комментарии:

1. Не удалось извлечь результирующий набор, вызванный: java.sql.SQLSyntaxErrorException: ORA-00923: ключевое слово FROM не найдено там, где ожидалось

2. все еще получаю FROM keyword not found where expected , но когда я копирую-вставляю запрос в sql developer, он работает отлично. Я действительно не понимаю: (

3. @MariusPop Попробуйте использовать сопоставление из моего обновленного ответа. Если это не поможет, пожалуйста hibernate.show_sql , включите hibernate.format_sql hibernate.use_sql_comments и посмотрите, какой именно запрос выполнен.

4. проблема заключалась в интервале. Я не знал, что sql склеивает все, поэтому некоторые слова также были склеены

5. Хорошо, да, я видел ваш вопрос по этому поводу.