Статьи

Добавление функции фильтрации на уровне объектов Hibernate в репозиторий Spring Data JPA

Оригинальная статья:  http://borislam.blogspot.hk/2012/07/adding-hibernate-entity-level-filter.html

Те, кто использовал функции фильтрации данных hibernate, должны знать, что он очень мощный. Вы можете определить набор критериев фильтрации для класса сущностей или коллекции. Spring data JPA — очень удобная библиотека, но у нее нет подходящих функций. В этой статье я покажу, как добавить функции фильтра гибернации на уровне объекта. Вы можете использовать эти функции при использовании  Hibernate Entity Manager . Мы можем просто определить аннотацию в интерфейсе вашей репозитории, чтобы включить эту функцию.

 Шаг 1. Определите фильтр на уровне объекта как обычно. Просто используйте hibernate @FilterDef аннотацию

@Entity
@Table(name = "STUDENT")
@FilterDef(name="filterBySchoolAndClass", parameters={@ParamDef(name="school", type="string"),@ParamDef(name="class", type="integer")})
public class Student extends GenericEntity implements Serializable {
  // add your properties ...
}


 Шаг 2. Определите две пользовательских аннотации. 

Эти две аннотации должны использоваться в ваших интерфейсах репозитория. С помощью этих аннотаций можно применить фильтр гибернации, определенный на шаге 1, к конкретному запросу.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityFilter {
 FilterQuery[] filterQueries() default  {};
}


@Retention(RetentionPolicy.RUNTIME)
public @interface FilterQuery {
 String name()  default "";
 String jpql()  default "";
}


 Шаг 3. Добавьте метод в базовый репозиторий JPA данных Spring. 

Этот метод будет читать аннотацию, которую вы определили (т. Е. @FilterQuery), и применить к запросу фильтр гибернации, просто развернув EntityManager. В этом методе вы можете указать параметр в своем фильтре гибернации, а также параметр в запросе.

Если вы не знаете, как добавить пользовательский метод в базовый репозиторий JPA данных Spring, см. Мою предыдущую статью о  том, как подробно настроить базовый репозиторий JPA данных Spring . В предыдущей статье вы можете видеть, что я намеренно предоставляю интерфейс репозитория (то есть свойство springDataRepositoryInterface) в GenericRepositoryImpl. Эти маленькие хитрости позволяют мне легко получить доступ к аннотации в интерфейсе репозитория.

public List<T> doQueryWithFilter( String filterName, String filterQueryName, Map inFilterParams, Map inQueryParams){
    if (GenericRepository.class.isAssignableFrom(getSpringDataRepositoryInterface())) {
       Annotation entityFilterAnn = getSpringDataRepositoryInterface().getAnnotation(EntityFilter.class);
       if(entityFilterAnn != null){
        EntityFilter entityFilter = (EntityFilter)entityFilterAnn;
        FilterQuery[] filterQuerys  = entityFilter.filterQueries() ;
        for (FilterQuery fQuery : filterQuerys) { 
         if (StringUtils.equals(filterQueryName, fQuery.name())) {
          String jpql = fQuery.jpql();
          Filter filter = em.unwrap(Session.class).enableFilter(filterName);
           
          //set filter parameter
          for (Object key: inFilterParams.keySet()) {
           String filterParamName = key.toString();
           Object filterParamValue = inFilterParams.get(key);
           filter.setParameter(filterParamName, filterParamValue);
                }
           
          //set query parameter
          Query query= em.createQuery(jpql);
          for (Object key: inQueryParams.keySet()) {
           String queryParamName = key.toString();
           Object queryParamValue = inQueryParams.get(key);
           query.setParameter(queryParamName, queryParamValue);
                }
          return query.getResultList();
         }
        }
       }
      }
     }
     return null;
    }
 

 Последний шаг: пример использования

В вашем репозитории определите, к какому запросу вы хотите применить фильтр гибернации, используя аннотации @EntityFilter и @FilterQuery.

@EntityFilter (
 filterQueries = {
   @FilterQuery(name="query1", 
       jpql="SELECT s FROM Student LEFT JOIN FETCH s.Subject where s.subject = :subject" ),
   @FilterQuery(name="query2", 
       jpql="SELECT s FROM Student LEFT JOIN s.TeacherSubject where s.teacher =  :teacher")       
 }
)
public interface StudentRepository extends GenericRepository<Student, Long> {
}

 

В вашем сервисе или бизнес-классе, который внедряет ваш репозиторий, вы можете просто вызвать метод doQueryWithFilter (), чтобы включить функцию фильтрации. 

@Service
public class StudentService {
 
 @Inject
 private StudentRepository studentRepository;
 
 public List<Student> searchStudent( String subject, String school, String class) {
    
  List<Student> studentList;
 
  // Prepare parameters for query filter
  HashMap<String, Object> inFilterParams = new HashMap<String, Object>();
  inFilterParams.put("school", "Hong Kong Secondary School");
  inFilterParams.put("class", "S5");
 
  // Prepare parameters for query
  HashMap<String, Object> inParams = new HashMap<String, Object>();
  inParams.put("subject", "Physics");
 
  studentList = studentRepository.doQueryWithFilter(
    "filterBySchoolAndClass", "query1",
    inFilterParams, inParams);
 
  return studentList;
 }
}