Поиск по множеству необязательных параметров в весеннем хранилище данных jpa - PullRequest
1 голос
/ 04 октября 2019

Так что у меня есть таблицы комментариев и автора. Я хочу построить сложную панель поиска со многими дополнительными параметрами. Я хочу отфильтровать комментарии с необязательным именем автора / фамилией и некоторыми флагами, такими как популярность (на основе рейтинга комментариев).

Поскольку я не знаю, как написать его, используя репозиторий Spring data jpa, я думал о том, чтобы написать его как нативныйзапрос с аннотацией @Query, что-то вроде этого должно работать

Select c.* from comment c join author a on a.id = c.author_id
Where (:firstname = '' or (:firstname = a.firstname)) 
And (:lastname = '' or (:lastname = a.lastname))
And (:popular = false or (c.rating > 25))

Есть ли возможность записать его, используя пружинные данные jpa?

В будущем я планирую добавить, например, дополнительные параметры и нумерацию страниц. Используя Spring, это будет как 1 минута с SQL-запросом, я потеряю несколько часов.

Существуют ли лучшие практики в таких случаях?

Ответы [ 2 ]

0 голосов
/ 04 октября 2019

Предлагаю использовать JpaSpecificationExecutor метод репозитория findAll(Specification<T> spec, Pageable pageable). Это решение позволяет расширять список параметров, используя один и тот же репозиторий и сервисный API

Сущности:

@Entity
@Table(name = "author")
public class Author {

    @Id
    @GeneratedValue
    @Column(name = "id")
    private Long id;

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

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

    // getters, setters, equals, hashcode, toString ...
}

@Entity
@Table(name = "comment")
public class Comment {

    @Id
    @GeneratedValue
    @Column(name = "id")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "author_id")
    Author author;

    @Column(name = "rating")
    Integer rating;

    // getters, setters, equals, hashcode, toString ...
}

Репозиторий:

@Repository
public interface CommentRepository 
    extends JpaRepository<Comment, Long>, JpaSpecificationExecutor<Comment> {

}

Технические характеристики: org.springframework.data.jpa.domain.Specification

public class CommentSpecs {

      /** if firstname == null then specification is ignored */
      public static Specification<Comment> authorFirstnameEquals(String firstname) {
        return (root, query, builder) -> 
             firstname == null ? 
                 builder.conjunction() :
                 builder.equal(root.get("author").get("firstname"), firstname);
      }

      /** if lastname == null then specification is ignored */
      public static Specification<Comment> authorLastnameEquals(String lastname) {
        return (root, query, builder) -> 
             lastname == null ? 
                 builder.conjunction() :
                 builder.equal(root.get("author").get("lastname"), lastname);
      }

      /** if rating == null then specification is ignored */
      public static Specification<Comment> ratingGreaterThan(Integer rating) {
        return (root, query, builder) -> 
             rating == null ? 
                 builder.conjunction() :
                 builder.greaterThan(root.get("rating"), rating);
      }
}

Параметры метода обслуживания:

public class CommentParameters {

  String authorFirstname;
  String authorLastname;
  Integer rating;

  // getters, setters

}

Все параметры обнуляются. Вы можете установить параметры, которые вам нужны только. Если параметр имеет значение null, он игнорируется нашими спецификациями

Сервис:

@Service
public class CommentService {

  @Autowired
  CommentRepository repository;

  public List<Comment> getComments(CommentParameters params, Pageable pageable) {

      Specification spec1 = CommentSpecs.authorFirstnameEquals(params.getAuthorFirstname());                                            
      Specification spec2 = CommentSpecs.authorLastnameEquals(params.getAuthorLastname());
      Specification spec3 = CommentSpecs.ratingGreaterThan(params.getRating());

      Specification spec = Specifications.where(spec1).or(spec2).or(spec3);

      return repository.findAll(spec, pageable);

   }
}

Я написал код с помощью текстового редактора, поэтому он нуждается в пересмотре. Но я думаю, что главное легко определить

0 голосов
/ 04 октября 2019

Вы можете использовать либо jpa, либо построитель критериев, если вы предпочитаете использовать JPA, вы можете сделать это следующим образом:

@Query("select s from SomeEntity s "
        + "where (s.description is null or s.description = :description) "
        + "and (s.name is null or s.name = :name) "
List<SomeEntity> find(String description, String name);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...