отображение сложного конструктора встроенного запроса hibernate

Java, Spring Данные JPA

У меня есть 2 сущности:

class Source {
  Integer id;
  String name;
}

class Item {
  Integer id;
  String name;
  Integer sourceId;
} 

Мне нужен статистический собственный результат запроса, например:

 select s.id source_id, s.name source_name, count(i.id) item_count
 from source s
 left join item i on s.id = i.source_id
 group by s.id 

И я хочу получить результат в объекте Java MyResult:

class MyResult {
  Source source;
  Integer itemCount;
  MyResult(Source source, Integer itemCount) {...}
}

Ближайшее решение - использовать @SqlResultSetMapping следующим образом:

@SqlResultSetMapping(
    name = "MyResultMapping",
    entities = {
        @EntityResult(
             entityClass = Source.class,
                fields = {
                    @FieldResult(name = "id", column = "source_id"),
                    @FieldResult(name = "name", column = "source_name"),
                }
        ),
        ... 
        ???
    }
)

OR

@SqlResultSetMapping(
    name = "MyResultMapping",
    classes = {
        @ConstructorResult(
            targetClass = MyResult.class,
                columns = {
                    @ColumnResult(name = "???"),
                    ???
                }
        )
    }
)

Со вторым вариантом я могу использовать что-то вроде этого:

MyResult(Integer sourceId, String sourceName, Integer itemsCount) {
    this.source = new Source(sourceId, sourceName);
    this.itemsCount = itemsCount;
}

но я хочу, чтобы это автоматизировалось с помощью @SqlResultSetMapping... (потому что мои реальные объекты более сложны)


person Elegant.Obj    schedule 14.04.2018    source источник


Ответы (1)


С Spring Data JPA лучше использовать проекции для достижения вам нужно, например:

public interface SourceWithItemCount {
    Source getSource();
    Integer getItemCount();
}

Затем в исходном репозитории создайте запрос HQL. метод, например:

public interface SourceRepo extends JpaRepository<Source, Integer> {
    @Query("select s as source, count(i) like itemCount from Source s left join Item i on i.sourceId = s.id group by s"
    List<SourceWithItemCount> getSourcesWithItemCount();
}

Важным примечанием является использование псевдонимов для возвращаемых значений (s as source и т. д.), это позволяет Spring Data JPA сопоставлять их со свойствами проекций.

Join on <condition> работает с Hibernate версии 5.1+ (если я не ошибаюсь), поэтому я рекомендую вам создать классический один ко многим между вашими объектами, например, так:

@Entity
class Source {
    @Id private Integer id;
    private String name;
    @OneToMany @JoinColumn(name = "source_id") private List<Item> items;
}

@Entity
class Item {
    @Id private Integer id;
    private String name;
} 

Затем создайте метод запроса JPQL, поддерживаемый всеми версиями Hibernate (и другими поставщиками ORM). ):

@Query("select s as source, count(i) like itemCount from Source s left join s.items i group by s"
List<SourceWithItemCount> getSourcesWithItemCount();
person Cepr0    schedule 15.04.2018
comment
Спасибо за проекционную ссылку и идею! это выглядит полезно, но моя ключевая проблема - собственное сопоставление запросов (мои сущности без прямых отношений, и я не могу использовать HQL) - person Elegant.Obj; 15.04.2018
comment
@Elegant.Obj Hibernate 5.1+ поддерживает соединение между несвязанными объектами, поэтому вы можете использовать HQL. - person Cepr0; 17.04.2018