2014-09-16 4 views
2

Я использую Spring Data для подкачки и сортировки. Однако я хотел бы выполнить поиск по нескольким столбцам.Spring Data - Многоколоночные поиски

Теперь я использую аннотацию @Query в моем хранилище интерфейс, как это:

public interface MyRepository extends PagingAndSortingRepository<Item,Long> { 

    @Query(value="select mt from MY_TABLE mt where mt.field1 = %searchtext% or mt.field2 = %searchtext% or mt.field3 = %searchtext%")  
    Page<Item> findByAllColumns(@Param("searchtext") String searchtext, Pageable pageable); 

} 

редактировать: Проблема в этом растворе находится в пункте где аннотации @Query, потому что мы имеем повторить тот же самый параметр поиска для каждого столбца, который мы хотим найти на (уточнение вопроса после комментария Брэндона Оукли)

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

Благодарим за помощь.

+0

Это может ответить на ваш вопрос ... http://stackoverflow.com/a/20121813/2267073 –

+0

Я не уверен, как: проблема в моем текущем растворе находится в ИНЕКЕ _ @ Query_ аннотации потому что мы должны повторить тот же самый параметр _searchtext_ для каждого столбца, который мы хотим найти. Поэтому я задаюсь вопросом, есть ли еще один более элегантный способ сделать это, чтобы мы могли просто указать имя столбцов. – jplandrain

+0

Ваш ответ очень интересный, но для других ситуаций. Итак, спасибо за предложение. – jplandrain

ответ

4

Вы можете использовать specifications. Это также дает вам большую гибкость. Вы можете иметь один метод, но использовать несколько спецификаций для запроса:

Page<Item> findAll(Specification<T> spec, Pageable pageable); 

myRepository.findAll(textInAllColumns(searchText), pageable); 
+0

Спасибо за указатель. В настоящее время мы проводим расследование, чтобы проверить, соответствует ли это нашей потребности. Это сообщение в блоге очень интересно: http: // spring.io/blog/2011/04/26/advanced-spring-data-jpa-specification-and-querydsl/ – jplandrain

+0

Это прекрасно работает, и это именно то, что мы искали: нам даже не нужно указывать аннотацию _Query_ , И Pagination все еще работает нормально. И это объектно-ориентированное (т. Е. Идеально многоразовое). Большое спасибо ! – jplandrain

+0

Хотя мы еще не использовали его, этот связанный проект также очень интересен: http://blog.kaczmarzyk.net/2014/03/23/alternative-api-for-filtering-data-with-spring-mvc- and-spring-data/ – jplandrain

5

Вот пример такой спецификации для пользователя:

public static Specification<User> containsTextInName(String text) { 
    if (!text.contains("%")) { 
     text = "%" + text + "%"; 
    } 
    String finalText = text; 
    return (root, query, builder) -> builder.or(
      builder.like(root.get("lastname"), finalText), 
      builder.like(root.get("firstname"), finalText) 
    ); 
} 

или даже более настраиваемый реализация:

public static Specification<User> containsTextInAttributes(String text, List<String> attributes) { 
    if (!text.contains("%")) { 
     text = "%" + text + "%"; 
    } 
    String finalText = text; 
    return (root, query, builder) -> builder.or(root.getModel().getDeclaredSingularAttributes().stream() 
      .filter(a -> attributes.contains(a.getName())) 
      .map(a -> builder.like(root.get(a.getName()), finalText)) 
      .toArray(Predicate[]::new) 
    ); 
} 

public static Specification<User> containsTextInName(String text) { 
    return containsTextInAttributes(text, Arrays.asList("lastname", "firstname")); 
} 

Использование:

userRepository.findAll(Specifications.where(UserSpecifications.containsTextInName("irs"))) 
1

Сочетание двух предыдущих ответов: если вы не хотите связывать свой API и схему базы данных или другими словами, вы не хотите, чтобы пользователь предоставлял имя столбца строки - вы можете отфильтровывать те атрибуты, которые не являются строками, и применять like всем тем, кто есть. В следующем примере он попытается найти text в значениях столбцов: name, field1, field2 и field3.

Сущность Пример:

@Entity 
public class MyEntity { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    public int id; 
    public String name; 
    public String field2; 
    public String field3; 
    public String field4; 
} 

Спецификация Пример:

public class EntitySpecification { 

    public static Specification<MyEntity> textInAllColumns(String text) { 

     if (!text.contains("%")) { 
      text = "%"+text+"%"; 
     } 
     final String finalText = text; 

     return new Specification<MyEntity>() { 
      @Override 
      public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> cq, CriteriaBuilder builder) { 
       return builder.or(root.getModel().getDeclaredSingularAttributes().stream().filter(a-> { 
        if (a.getJavaType().getSimpleName().equalsIgnoreCase("string")) { 
         return true; 
        } 
        else { 
         return false; 
       }}).map(a -> builder.like(root.get(a.getName()), finalText) 
        ).toArray(Predicate[]::new) 
       ); 
      } 
     }; 
    } 

} 

Repository Пример: Пример

public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, Integer> { 
    List<MyEntity> findAll(Specification<MyEntity> spec); 
} 

Использование:

List<MyEntity> res = failureRepository.findAll(Specifications.where(FailureSpecification.textInAllColumns(text))); 
Смежные вопросы