Spring - проекции JPA разрешаются по порядку интерфейса метода, а не по имени при наличии аннотации `@ Query`? - PullRequest
0 голосов
/ 14 октября 2019

Насколько я понимаю, при создании проекции в Spring JPA поля разрешаются по имени.

Похоже, что это не так при использовании @Query аннотаций.

Isэто ожидаемое поведение или что-то не так с моим запросом?

Допустим, у меня есть сущность

@Entity
@Table(name = "foo")
public class Foo {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Integer id;

    @Column(name = "code")
    private String code;

    @Column(name = "name")
    private String name;

    ... much more that we are not interested in ...
}

Мы просто хотим извлечь свойства id, name и code,Итак, давайте напишем простой интерфейс проекции:

@Repository
public interface FooRepository extends JpaRepository<Foo, Integer> {
    FooTestProjection findOneByCode(String code);

    interface FooTestProjection {
        Integer getId();

        String getName();

        String getCode();
    }
}

И тест для проверки того, что мы делаем:

@Test
void fooTestProjections() {
    Foo targetFoo = repository.saveAndFlush(testData.getFoo());

    getEntityManager().clear();

    FooTestProjection testProjection = repository.findOneByCode(targetFoo.getCode());

    assertThat(testProjection.getId()).isEqualTo(targetFoo.getId());
    assertThat(testProjection.getName()).isEqualTo(targetFoo.getName());
    assertThat(testProjection.getCode()).isEqualTo(targetFoo.getCode());

}

РАБОТЫ

Ожиданиездесь, это то, что свойства разрешаются по имени. Итак, давайте переключим getCode() и getName() в нашем интерфейсе проекции:

interface FooTestProjection {
    Integer getId();

    String getCode();

    String getName();
}

Да, все еще РАБОТАЕТ .

Теперь, скажем, мы хотим проекциидля всех наших Foo с, и мы хотим сделать это, используя @Query.

(Мотивация: в конечном итоге мы хотим построить проекцию, содержащую свойства несвязанных таблиц, поэтому мы используем @Query для LEFT JOIN их.)

Итак, давайте настроим наш метод хранилища:

@Repository
public interface FooRepository extends JpaRepository<Foo, Integer> {
    @Query("SELECT" +
        " f.id AS fooId," +
        " f.name AS fooName," +
        " f.code AS fooCode" +
        " FROM Foo  f"
    )
    List<FooTestProjection> findProjections();

    interface FooTestProjection {
        Integer getFooId();

        String getFooName();

        String getFooCode();
    }
}

и наш тест:

@Test
void fooTestProjections() {
    Foo targetFoo = repository.saveAndFlush(testData.getFoo());

    getEntityManager().clear();

    FooTestProjection testProjection = repository.findProjections().get(0);

    assertThat(testProjection.getFooId()).isEqualTo(targetFoo.getId());
    assertThat(testProjection.getFooName()).isEqualTo(targetFoo.getName());
    assertThat(testProjection.getFooCode()).isEqualTo(targetFoo.getCode());
}

РАБОТАЕТ

Тест зеленый, все в порядке, нет?

Нет.

Мы ожидали, что Spring будет смотреть на набор результатов, который мы создаем, и сопоставлять ихк интерфейсу проекции через псевдоним столбца, который мы определяем.

Это не так.

Давайте переключим getFooCode() и getFooName() в нашем интерфейсе, , но не в нашемquery :

@Query("SELECT" +
    " f.id AS fooId," +
    " f.name AS fooName," +
    " f.code AS fooCode" +
    " FROM Foo  f"
)
List<FooTestProjection> findProjections();

interface FooTestProjection {
    Integer getFooId();

    String getFooCode();

    String getFooName();
}

FAILS

Почему происходит сбой? Поскольку сейчас , getFooCode() возвращает name targetFoo, а getfooName() возвращает code targetFoo.

Так что если мы переключим выбораргументы, чтобы снова соответствовать порядку интерфейса ...

@Query("SELECT" +
    " f.id AS fooId," +
    " f.code AS fooCode," +
    " f.name AS fooName" +
    " FROM Foo  f"
)
List<FooTestProjection> findProjections();

interface FooTestProjection {
    Integer getFooId();

    String getFooCode();

    String getFooName();
}

Это РАБОТАЕТ снова.

Я нахожу это чрезвычайно нелогичным до того, что я подвергаю сомнениюправильность моего запроса.

Буду признателен, если кто-нибудь сможет пролить свет на это поведение.

...