Spring JPA: выбор определенных столбцов при объединении с аннотацией / JPQL - PullRequest
0 голосов
/ 18 сентября 2018

Я пытаюсь познакомиться с весной и jpa.Для запуска есть таблица anime_details , содержащая подробности аниме.Поскольку он может иметь много жанров, у db есть еще одна таблица с именем genre .Промежуточная таблица, которая будет содержать их много-много записей отношений, также находится там.Когда я запрашиваю любое аниме по идентификатору, он должен возвращать детали аниме вместе с жанрами.

Он возвращает объект с деталями аниме и списком объектов жанра (как и ожидалось).Но я хочу ограничить столбцы, которые будут выбираться из объектов жанра.Например, только идентификатор или только идентификатор и имя (в случае, если столбцов больше, чем эти).

AnimeDetails

@Getter
@Setter
@Entity
@Table(name = "anime_details")
public class AnimeDetails {
    @Id
    @SequenceGenerator(name = "animeDetailsSeq", sequenceName =
        "anime_details_id_seq",
        allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
        "animeDetailsSeq")
    private Integer id;

    private String name;
    private Integer episodes;
    private Date started;
    private Date ended;
    private String status;

    @ManyToMany
    @JoinTable(
        name = "anime_genre",
        joinColumns = @JoinColumn(name = "details_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "genre_id", referencedColumnName = "id"))
    @JsonManagedReference
    private List<Genre> genres;

    protected AnimeDetails() {
    }
}

Жанр

@Data
@Entity
@Table(name = "genre")
public class Genre {
    @Id
    @SequenceGenerator(name = "genreSeq", sequenceName = "genre_id_seq",
        allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "genreSeq")
    private Integer id;
    private String name;

    @ManyToMany(mappedBy = "genres")
    List<AnimeDetails> animes;

    protected Genre() {

    }
}

Ожидаемая полезная нагрузка

 {
    "id": 2,
    "name": "Your Name",
    "episodes": 1,
    "started": "2016-08-25T18:00:00.000+0000",
    "ended": "2016-08-25T18:00:00.000+0000",
    "status": "Completed",
    "genres": [
        {
            "id": 5,
            "name": "Drama"
        },
        {
            "id": 10,
            "name": "Supernatural"
        }
    ]
}

Прямо сейчас я получаю результат и вручную получаю столбцы один за другим и устанавливаю их в DTO.Но это неэффективно, поскольку запрос к базе данных уже извлекает больше данных, чем необходимо.Есть ли какая-нибудь конкретная аннотация / свойство / jpql для ее уменьшения?

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Сегодня я попробовал другое решение.Давайте сначала посмотрим на код.

Жанр

@Data
@Entity
@Table(name = "genre")
public class Genre {
    @Id
    @SequenceGenerator(name = "genreSeq", sequenceName = "genre_id_seq",
        allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "genreSeq")
    private Integer id;
    private String name;

    @ManyToMany
    @JoinTable(
        name = "anime_genre",
        joinColumns = @JoinColumn(name = "genre_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "details_id", referencedColumnName = "id"))
    List<AnimeIdentity> animes;

    protected Genre() {

    }
}

AnimeIdentity

@Getter
@Setter
@Entity
@Table(name = "anime_details")
public class AnimeIdentity {
    @Id
    @SequenceGenerator(name = "animeDetailsSeq", sequenceName =
        "anime_details_id_seq",
        allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
        "animeDetailsSeq")
    private Integer id;

    private String name;

    protected AnimeIdentity() {};
}

Запросы Hibernatemade

Hibernate: select genre0_.id as id1_2_0_, genre0_.name as name2_2_0_ from genre genre0_ where genre0_.id=?<br>
Hibernate: select animes0_.genre_id as genre_id2_1_0_, animes0_.details_id as details_1_1_0_, animeident1_.id as id1_0_1_, animeident1_.name as name2_0_1_ from anime_genre animes0_ inner join anime_details animeident1_ on animes0_.details_id=animeident1_.id where animes0_.genre_id=?

Не стесняйтесь показывать мне плюсы и минусы этого решения.Для меня это хорошее решение, если моя необходимость ограничена только этим.Но в случае запросов различного типа создание все большего числа сущностей будет утомительной задачей.

0 голосов
/ 19 сентября 2018

Действительно искал правильное решение в отношении той же проблемы, потому что, как вы указали, это создает проблемы с производительностью, поскольку между приложением и базой данных возникают огромные бесполезные загрузки данных.Представьте, что может быть не только один запрос, но и гораздо больше, и вам нужно глобальное решение по оптимизации ...

  • С самого начала Spring DATA не поддерживает эту операцию, поэтому вы ведете васпри ручной настройке и настройке по ссылке DTO.То же самое применимо, если вы использовали пользовательский объект и возвращали его внутри JPQL с помощью трюка с конструктором, или же пишете собственный запрос, возвращаете List<Object> и снова вручную сопоставляете данные с вашим реальным объектом, который является наиболееэффективное, но не элегантное решение. Больше информации в этой ссылке , но попробуйте проверить оба ответа для получения подробной информации.

  • Другое дело, что при использовании спящего режима внизу, который предоставляет пользовательские преобразователи, вы всегда можете написать свой собственный HQL (не jpql), настроить надлежащий DAO, подключить EntityManager или непосредственно SessionFactory (который нарушает абстрактный JPA-контракт, но вы можете использовать все положительные моментыв спящем режиме) и затем возвращает тот же объект, но только с нужными вам столбцами.

Пример для второй точки:

import javax.persistence.EntityManager;
import org.hibernate.query.Query;
import org.hibernate.transform.Transformers;

public CustomEntity getEntity(){
        Query<CustomEntity> q = (Query<CustomEntity>) entityManager.createQuery("select 
                         e.id,e.name from CustomEntity e where e.name = 'parameter'");
        q.setResultTransformer(Transformers.aliasToBean(CustomEntity.class));
        CustomEntity entity = (CustomEntity) q.getSingleResult();
        return name;
    }

Примечание CustomEntityуправляемый объектный компонент / таблица в базе данных, просто поместите этот пример, чтобы быть ближе к тому, что вам может понадобитьсяhieve.

Пробовал с

  • Spring boot 2.0.5.RELEASE
  • Spring Data 2.0.5.RELEASE
  • Hibernate-core 5.2.17.Final
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...