2016-07-22 113 views
2

Springデータjpaと仕様を使用して、spring mvcでフィルタ/検索機能を実装する必要があります。バックエンドは、基本的にフロントエンドのフィルタを表すいくつかのフィールドを持つBeanであるオブジェクト(ReportTemplateBean)を受け取ります。SpringデータJPAの動的クエリ。リファクタリング

public class ReportTemplateBean implements Serializable { 

private static final long serialVersionUID = -3915391620260021813L; 

private Long id; 

private String property; 

private String city; 

private String state; 

private String zipCode; 

private String propertyStatus; 

private String realEstateRep; 
//more code 

私たちは、コントローラ

@RequestMapping(value = "/search", method = RequestMethod.GET) 
@ResponseBody 
public ReportBean search(@AuthenticationPrincipal ActiveUser activeUser, 
    @ModelAttribute("templateForm") ReportTemplateBean template, 
    Pageable pageable) throws GenericException { 
LOGGER.info("Pulling report requested"); 

ReportBean report = reportService.searchProperties(template, 
    pageable.getPageNumber(), pageable.getPageSize()); 

return report; 
} 

サービス

@Override 
@Transactional(readOnly = true, timeout = 20) 
public ReportBean searchProperties(ReportTemplateBean template, 
    Integer pageNumber, Integer pageSize) throws GenericException, 
    TransactionTimedOutException { 
LOGGER.info("searchProperties({})", template); 

try { 
    // pageNumber = (pageNumber == null ? 0 : pageNumber); 
    // pageSize = (pageSize == null ? 10 : pageSize); 
    ReportTemplate t = reportTemplateMapper.beanToEntity(template); 
    List<PropertyBean> beans = new ArrayList<PropertyBean>(); 
    PropertySpecification spec = new PropertySpecification(t); 
    Page<Property> properties = propertyRepository.findAll(spec, 
     new PageRequest(pageNumber, pageSize, Sort.Direction.ASC, 
      "name")); 

を持っているし、それが動的にクエリを構築しますが、私はそれを好きではないIF長鎖を使用。これが仕様です。あなたが仕様に気づくことができたよう

@SuppressWarnings("unchecked") 
@Override 
public Predicate toPredicate(Root<Property> root, CriteriaQuery<?> query, 
    CriteriaBuilder cb) { 
Path<String> propertyName = root.get(Property_.name); 
Path<String> city = root.get(Property_.city); 
Path<String> state = root.get(Property_.state); 
Path<String> zipCode = root.get(Property_.zipCode); 
final List<Predicate> orPredicates = new ArrayList<Predicate>(); 
final List<Predicate> andPredicates = new ArrayList<Predicate>(); 
if (template.getProperty() != null 
    && template.getProperty().length() > 0) { 
    andPredicates.add(cb.equal(propertyName, template.getProperty())); 
} 
if (template.getCity() != null && template.getCity().length() > 0) { 
    andPredicates.add(cb.equal(city, template.getCity())); 
} 
if (template.getState() != null && template.getState().length() > 0) { 
    andPredicates.add(cb.equal(state, template.getState())); 
} 
if (template.getZipCode() != null && template.getZipCode().length() > 0) { 
    andPredicates.add(cb.equal(zipCode, template.getZipCode())); 
} 
if (template.getRealEstateRep() != null) { 
    Join<Property, User> pu = null; 
    if (query.getResultType().getName().equals("java.lang.Long")) { 
    pu = (Join<Property, User>) root.fetch(Property_.createdBy); 
    } else { 
    pu = root.join(Property_.createdBy); 
    } 
    Path<Long> userId = pu.get(User_.id); 
    andPredicates.add(cb.equal(userId, template.getRealEstateRep())); 
} 
if (template.getProjectType() != null 
    && template.getProjectType().length() > 0) { 
    Join<Property, Project> pp = null; 
    if (query.getResultType().getName().equals("java.lang.Long")) { 
    pp = root.join(Property_.projects); 
    } else { 
    pp = (Join<Property, Project>) root.fetch(Property_.projects); 
    } 
    Path<String> projectType = pp.get(Project_.projectName); 
    andPredicates.add(cb.equal(projectType, template.getProjectType())); 
} 
//more IF's 
return query.getRestriction(); 
} 

は醜いようで、そのSONARのほかに(良い)このメソッドの循環的複雑度について不平を言います。

質問ですが、どうすれば仕様(IF)をより多くのOOコードにリファクタリングできますか。 ありがとうございます。 UPDATE - 私はSpring Data JPA(Query by Example)の新機能のようなものを使用/実装したいと思います。ExampleMatcherクラスは、Beanフィールドのnull値をほとんど無視しているようですを探しています。 null値と空の値は無視します。

+0

仕様のみを使用してソリューションをお探しですか?私は同様の問題を抱えていましたが、私はリポジトリにオプションのパラメータを使って@Queryアノテーションを使ってクエリを書くことで解決しました – amicoderozer

+0

仕様を使用していいですが、必須ではありません。 – TheProgrammer

答えて

0

私はあなたに別のオプションを与えるために私の解決策を書いていますが、私がコメントで言うように私は仕様を使用していません、そして、誰かがspring jpaで動的クエリを行う別の方法を知っているかどうか知りたいです。

@Query注釈付きの独自のクエリを@Repositoryインターフェイス内に記述することができます。あなたのケースでは (ReportTemplateBeanと仮定すると、あなたのエンティティであり、その主キーがロング型である)、それは次のようになります:ときはnullとして渡し、あなたが望むすべてのパラメータを追加することができます

@Repository 
public interface ReportTemplateRepo extends JpaRepository<ReportTemplateBean, Long>{ 

    @Query("SELECT rb FROM ReportBeanTemplate rb JOIN ExampleTable et WHERE et.idTemplate = rb.id AND (:id is null OR :id = rb.id) AND (:city is null OR :city = rb.city) AND (:state is null OR :state = rb.state)") 
    public List<ReportTemplateBean> findTemplates(@Param("id") Long id, @Param("city") String city, @Param("state") String state); 
} 

メソッドを呼び出します。 (あなたのサービスクラスの)メソッド呼び出しの

例:

@Autowire 
ReportTemplateRepo templateRepo; 

public void invocation(ReportTemplateBean template){ 
    List<ReportTemplateBean> templateRepo.findTemplates(
     template.getId(), template.getCity(), template.getState()); 
    } 

これは、私は、クエリのこの種を行うに見つけた唯一の方法です。

+0

関係があればどうなりますか?私のBeanはOneToOneとOneToManyの関係を持っています。あなたのソリューションはこれを管理できますか?どのようにしてnullがいつですか?ありがとう。 – TheProgrammer

+0

私はまだ私のプロジェクトでOneToManyの関係を持っていないので、私はテストしていませんが、この質問を見てくださいhttp://stackoverflow.com/questions/38614247/default-sort-on-a-spring-data -jpa-repository-method-with-custom-query-and-pageab。彼はダイナミックなパラメータとの関係とクエリを使用し、彼はそれが動作すると言います。しかし、私はnullの場合この種の関係を管理する方法を知らない – amicoderozer

+0

ありがとう@amicoderozer、この情報は非常に便利です。 – TheProgrammer

関連する問題