2016-07-27 3 views
2

У меня есть Post и Tag модели, у которых есть @manytomany отношения.Весенние данные JPA Возможно с @ManyToMany

Сообщение

@Entity 
public class Post { 
    private long id; 

    @ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) 
    @JoinTable(joinColumns = @JoinColumn(name = "post_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) 
    private Set<Tag> tags; 

    ... 
} 

Tag

@Entity 
public class Tag { 
    private String name; 

    @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy = "tags") 
    private List<Post> posts = new ArrayList<Post>(); 

Я хотел бы сделать метод, который находит все нумерованных страниц по имени тега.

Я выяснил, что JPQL не поддерживает LIMIT.

Должен ли я реализовать свою собственную логику подкачки, используя setFirstResult().setMaxResults().getResultList()?

Какова наилучшая практика для разбивки на страницы @manytomany?

Я немного отредактировал свой вопрос. Я написал свои коды, как показано ниже:

@SuppressWarnings("unchecked") 
public Page<Post> findByTagName(String tagName, Pageable pageable) { 

    long total = (long) em 
      .createQuery("SELECT COUNT(p.id) FROM Post p JOIN p.tags t WHERE t.name = :tagName") 
      .setParameter("tagName", tagName) 
      .getSingleResult(); 

    List<Post> content = (List<Post>) em 
      .createQuery("SELECT p FROM Post p JOIN FETCH p.tags t WHERE t.name = :tagName") 
      .setParameter("tagName", tagName) 
      .setFirstResult(pageable.getOffset()) 
      .setMaxResults(pageable.getPageSize()) 
      .getResultList(); 

    PageImpl<Post> page = new PageImpl<Post>(content, pageable, total); 

    return page; 
} 

Этот код работает нормально, но мне все еще интересно, правильно ли это.

спасибо.

+0

я не вижу, где вы используете '[весна-данных JPA]' –

+0

@RobertNiestroj Я хотел бы использовать [весна-данные -jpa], но не похоже, что он поддерживает JPQL с ограничением и JOIN. В качестве альтернативы я применил пользовательский метод, используя [em]. Надеюсь, он возвращает многоразовый тип [Страница]. Поэтому мне интересно, что я поступаю правильно. Спасибо. – nasiajai

ответ

0

Не уверен, что, если он работает в вашем случае, но проверить эту ссылку

setMaxResults for Spring-Data-JPA annotation?

Кроме того,

Вы можете использовать FindFirst или findTop методы предела весной JPA.

http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.limit-query-result

+0

Я знаю, как использовать Pageableable, first или top с «единственным» объектом. Однако, похоже, он не поддерживает отношения «многие ко многим». Таким образом, я редактировал свой вопрос, и я добавил некоторые коды. Пожалуйста, дайте мне знать ваше мнение. Спасибо. – nasiajai

1

Работа со страницами и @ManyToMany отображение является очень простой задачей.

Прежде всего, это модели, похожие на ваши (в основном добавлены @Id и @GeneratedValue аннотации для получения сгенерированных идентификаторов базы данных).

Сообщение лицо:

package com.example.model; 

import java.util.HashSet; 
import java.util.Set; 

import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.FetchType; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.JoinTable; 
import javax.persistence.ManyToMany; 

@Entity 
public class Post { 

    @Id 
    @GeneratedValue 
    private long id; 

    @ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) 
    @JoinTable(joinColumns = @JoinColumn(name = "post_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) 
    private Set<Tag> tags = new HashSet<>(); 

    public Set<Tag> getTags() { 
     return tags; 
    } 

} 

Tag объект:

package com.example.model; 

import java.util.ArrayList; 
import java.util.List; 

import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.FetchType; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.ManyToMany; 

@Entity 
public class Tag { 

    @Id 
    @GeneratedValue 
    private long id; 

    private String name; 

    @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy = "tags") 
    private List<Post> posts = new ArrayList<Post>(); 

    public void setName(String name) { 
     this.name = name; 
    } 

} 

Теперь вам нужно PagingAndSortingRepository для выборки почтовые объекты:

package com.example.repository; 

import java.util.Set; 

import org.springframework.data.domain.Page; 
import org.springframework.data.domain.Pageable; 
import org.springframework.data.repository.PagingAndSortingRepository; 
import org.springframework.stereotype.Repository; 
import org.springframework.transaction.annotation.Transactional; 

import com.example.model.Post; 

@Repository 
public interface PostRepository extends PagingAndSortingRepository<Post, Long> { 

    @Transactional(readOnly = true) 
    Set<Post> findByTagsName(String name); 

    @Transactional(readOnly = true) 
    Page<Post> findByTagsName(String name, Pageable pageable); 

} 

Работа с pagables почти так же просто, как написание регулярных методов поиска данных JPA Spring. Если вы хотите найти сообщения по именам назначенных тегов, просто напишите регулярный искатель, объединив имена полей, такие как findBy Tags + Name. Это создает запрос, похожий на ваш подход JPQL SELECT p FROM Post p JOIN FETCH p.tags t WHERE t.name = :tagName. Передайте параметр для имени тега только как параметр метода.

Теперь - если вы хотите добавить поддержку страниц - просто добавьте параметр типа Pageable в качестве второго параметра и верните возвращаемое значение в Page вместо Set. Это все.

По крайней мере, вот некоторые тесты, чтобы проверить, код:

package com.example.repository; 

import static org.hamcrest.CoreMatchers.is; 
import static org.hamcrest.Matchers.empty; 
import static org.hamcrest.Matchers.hasSize; 
import static org.junit.Assert.assertThat; 

import java.util.Set; 

import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.data.domain.Page; 
import org.springframework.data.domain.PageRequest; 
import org.springframework.test.context.junit4.SpringRunner; 
import org.springframework.transaction.annotation.Transactional; 

import com.example.model.Post; 
import com.example.model.Tag; 

@RunWith(SpringRunner.class) 
@Transactional 
@SpringBootTest 
public class PostRepositoryTests { 

    @Autowired 
    private PostRepository postRepository; 

    @PersistenceContext 
    private EntityManager entityManager; 

    @Test 
    public void receiveMultiplePostsWithTagsByName() { 
     final String nameA = "A"; 
     final String nameB = "B"; 
     final String nameC = "C"; 
     final String nameD = "D"; 
     final String nameE = "E"; 

     final Tag tagA = new Tag(); 
     tagA.setName(nameA); 
     final Tag tagB = new Tag(); 
     tagB.setName(nameB); 
     final Tag tagC = new Tag(); 
     tagC.setName(nameC); 
     final Tag tagD = new Tag(); 
     tagD.setName(nameD); 
     final Tag tagE = new Tag(); 
     tagE.setName(nameE); 

     final Post postOne = new Post(); 
     postOne.getTags().add(tagA); 
     postOne.getTags().add(tagB); 
     postRepository.save(postOne); 

     final Post postTwo = new Post(); 
     postTwo.getTags().add(tagA); 
     postTwo.getTags().add(tagB); 
     postTwo.getTags().add(tagE); 
     postRepository.save(postTwo); 

     final Post postThree = new Post(); 
     postThree.getTags().add(tagA); 
     postThree.getTags().add(tagB); 
     postThree.getTags().add(tagC); 
     postThree.getTags().add(tagE); 
     postRepository.save(postThree); 

     entityManager.flush(); 
     entityManager.clear(); 

     final Set<Post> tagsByA = postRepository.findByTagsName(nameA); 
     assertThat("Expected three hits!", tagsByA, hasSize(3)); 

     final Set<Post> tagsByB = postRepository.findByTagsName(nameB); 
     assertThat("Expected three hits!", tagsByB, hasSize(3)); 

     final Set<Post> tagsByC = postRepository.findByTagsName(nameC); 
     assertThat("Expected one hit!", tagsByC, hasSize(1)); 

     final Set<Post> tagsByD = postRepository.findByTagsName(nameD); 
     assertThat("Expected no hits!", tagsByD, empty()); 

     final Set<Post> tagsByE = postRepository.findByTagsName(nameE); 
     assertThat("Expected two hits!", tagsByE, hasSize(2)); 
    } 

    @Test 
    public void receiveMultiplePostsWithTagsByNamePaged() { 
     final String nameA = "A"; 

     final Tag tagA = new Tag(); 
     tagA.setName(nameA); 

     final Post postOne = new Post(); 
     postOne.getTags().add(tagA); 
     postRepository.save(postOne); 

     final Post postTwo = new Post(); 
     postTwo.getTags().add(tagA); 
     postRepository.save(postTwo); 

     final Post postThree = new Post(); 
     postThree.getTags().add(tagA); 
     postRepository.save(postThree); 

     final Post postFour = new Post(); 
     postFour.getTags().add(tagA); 
     postRepository.save(postFour); 

     final Post postFive = new Post(); 
     postFive.getTags().add(tagA); 
     postRepository.save(postFive); 

     entityManager.flush(); 
     entityManager.clear(); 

     final Page<Post> tagsByAFirstPageSize2 = postRepository.findByTagsName(nameA, new PageRequest(0, 2)); 
     assertThat("Expected two page items!", tagsByAFirstPageSize2.getContent(), hasSize(2)); 
     assertThat("Expected five items in sum!", tagsByAFirstPageSize2.getTotalElements(), is(5L)); 
     assertThat("Should be first page!", tagsByAFirstPageSize2.isFirst(), is(true)); 
     assertThat("Should not be last page!", tagsByAFirstPageSize2.isLast(), is(false)); 

     final Page<Post> tagsBySecondPageSize2 = postRepository.findByTagsName(nameA, new PageRequest(1, 2)); 
     assertThat("Expected two page items!", tagsBySecondPageSize2.getContent(), hasSize(2)); 
     assertThat("Expected five items in sum!", tagsBySecondPageSize2.getTotalElements(), is(5L)); 
     assertThat("Should not be first page!", tagsBySecondPageSize2.isFirst(), is(false)); 
     assertThat("Should not be last page!", tagsBySecondPageSize2.isLast(), is(false)); 

     final Page<Post> tagsByLastPageSize2 = postRepository.findByTagsName(nameA, new PageRequest(2, 2)); 
     assertThat("Expected one last page item!", tagsByLastPageSize2.getContent(), hasSize(1)); 
     assertThat("Expected five items in sum!", tagsByLastPageSize2.getTotalElements(), is(5L)); 
     assertThat("Should not be first page!", tagsByLastPageSize2.isFirst(), is(false)); 
     assertThat("Should be last page!", tagsByLastPageSize2.isLast(), is(true)); 
    } 

} 
Смежные вопросы