Эффективный способ получить размер списка - PullRequest
0 голосов
/ 06 апреля 2020

У меня есть сущность, как показано ниже. Когда мне нужно указать размер комментария компании, я вызываю метод totalComments (). Для этого ли hibernate go в базу данных и получить все данные комментария или просто запрос с count (*)? Если hibernate получает весь комментарий, каков эффективный способ получения размера комментария?


@Entity
@Table(name = "companies")
public class Company extends ItemEntity {

    @OneToMany(fetch = FetchType.LAZY)
    @JoinTable(name="companies_comments",
            joinColumns=@JoinColumn(name="company_id"),
            inverseJoinColumns=@JoinColumn(name="comment_id"))
    private Set<Comment> comments = new HashSet<>();

    public void addComment(Comment comment) {
        this.comments.add(comment);
    }

    public int totalComments() {
        return this.comments.size();
    }
}

Ответы [ 2 ]

0 голосов
/ 06 апреля 2020

Я нашел ответ. Если мы не настроены на получение размера коллекции, спящий объект загружает каждый комментарий. Мы можем решить эту проблему производительности двумя способами.

Мы можем использовать @LazyCollection(LazyCollectionOption.EXTRA), как показано ниже. LazyCollectionOption.EXTRA .size() и .contains() не будут инициализировать всю коллекцию.

@OneToMany(fetch = FetchType.LAZY)
@LazyCollection(LazyCollectionOption.EXTRA)
@JoinTable(name="companies_comments",
        joinColumns=@JoinColumn(name="company_id"),
        inverseJoinColumns=@JoinColumn(name="comment_id"))
private Set<Comment> comments = new HashSet<>();

Или мы можем использовать аннотацию @Formula.

@Formula(SELECT COUNT(*) FROM companies_comments cc WHERE cc.company_id = id)
private int numberOfComments;
0 голосов
/ 06 апреля 2020

Вы должны удалить собственный счетчик методов и создать конкретный c (бизнес) запрос для получения размера списка, например

public long getCommentsCount(Company c) {
    String query = "SELECT COUNT(cm) FROM Company AS c JOIN c.comments AS cm WHERE c = :company";
    return entityManager.createQuery(q, Long.class).setParameter("company", c).getSingleResult();
}

Некоторые поставщики персистентности могут оптимизировать производительность, когда такого рода запрос загружается в виде @NamedQuery для объекта или при использовании CriteriaQuery API. В зависимости от вашей базы данных вам может потребоваться изменить класс возврата на Number.class и преобразовать в long.

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

...