GithubHelp home page GithubHelp logo

fendaq / jpa-spec Goto Github PK

View Code? Open in Web Editor NEW

This project forked from wenhao/jpa-spec

0.0 1.0 0.0 283 KB

A JAP Query By Specification framework.

License: Apache License 2.0

Shell 1.08% Java 98.92%

jpa-spec's Introduction

Build Status Coverage Status ๐Ÿ‡จ๐Ÿ‡ณ

jpa-spec

Inspired by Legacy Hibernate Criteria Queries, while this should be considered deprecated vs JPA APIs,

but it still productive and easily understandable. Build on Spring Data JPA and simplify the dynamic query process.

Features

  • Compatible with Spring Data JPA and JPA 2.1 interface.
  • Equal/NotEqual/Like/NotLike/In/NotIn support multiple values, Equal/NotEqual support Null value.
  • Each specification support join query(left joiner).
  • Support custom specification.
  • Builder style specification creator.
  • Support pagination and sort builder.

Docs

English Version:

Latest

3.2.4

3.2.1

3.1.0

3.0.0

Chinese Version:

ๆœ€ๆ–ฐ

3.2.4_cn

3.2.1_cn

3.1.0_cn

3.0.0_cn

Gradle

repositories {
    jcenter()
}

dependencies {
    compile 'com.github.wenhao:jpa-spec:3.2.4'
}

Maven

<dependency>
    <groupId>com.github.wenhao</groupId>
    <artifactId>jpa-spec</artifactId>
    <version>3.2.4</version>
</dependency>

Build

./gradlew clean jTCV jTR build

Specification By Examples:

Each specification support three parameters:

  1. condition: if true(default), apply this specification.
  2. property: field name.
  3. values: compare value with model, eq/ne/like support multiple values.

General Example

each Repository class should extends from two super class JpaRepository and JpaSpecificationExecutor.

public interface PersonRepository extends JpaRepository<Person, Long>, JpaSpecificationExecutor<Person> {
}    
public Page<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .eq(StringUtils.isNotBlank(request.getName()), "name", request.getName())
            .gt(Objects.nonNull(request.getAge()), "age", 18)
            .between("birthday", new Date(), new Date())
            .like("nickName", "%og%", "%me")
            .build();

    return personRepository.findAll(specification, new PageRequest(0, 15));
}

Equal/NotEqual Example

find any person nickName equals to "dog" and name equals to "Jack"/"Eric" or null value, and company is null.

Test: EqualTest.java and NotEqualTest.java

public List<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .eq("nickName", "dog")
            .eq(StringUtils.isNotBlank(request.getName()), "name", "Jack", "Eric", null)
            .eq("company", null) //or eq("company", (Object) null)
            .build();

    return personRepository.findAll(specification);
}

In/NotIn Example

find any person name in "Jack" or "Eric" and company not in "ThoughtWorks" or "IBM".

Test: InTest.java

public List<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .in("name", request.getNames().toArray()) //or in("name", "Jack", "Eric")
            .notIn("company", "ThoughtWorks", "IBM")
            .build();

    return personRepository.findAll(specification);
}

Comparison Example

Support any comparison class which implements Comparable interface, find any people age bigger than 18.

Test: GreatThanTest.java

public List<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .gt(Objects.nonNull(request.getAge()), "age", 18)
            .lt("birthday", new Date())
            .build();

    return personRepository.findAll(specification);
}

Between Example

find any person age between 18 and 25, birthday between someday and someday.

Test: BetweenTest.java

public List<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .between(Objects.nonNull(request.getAge(), "age", 18, 25)
            .between("birthday", new Date(), new Date())
            .build();

    return personRepository.findAll(specification);
}  

Like/NotLike Example

find any person name like %ac% or %og%, company not like %ec%.

Test: LikeTest.java and NotLikeTest.java

public Page<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .like("name", "ac", "%og%")
            .notLike("company", "ec")
            .build();

    return personRepository.findAll(specification);
}

Or

support or specifications.

Test: OrTest.java

public List<Phone> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>or()
                    .like("name", "%ac%")
                    .gt("age", 19)
                    .build();

    return phoneRepository.findAll(specification);
}

Mixed And and Or

support mixed and and or specifications.

Test: AndOrTest.java

public List<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
                    .like("name", "%ac%")
                    .predicate(Specifications.or()
                            .lt("age", 19)
                            .gt("age", 25)
                            .build())
                    .build();

    return personRepository.findAll(specification);
}

Join

each specification support association query as left join.

Test: JoinTest.java

@ManyToOne association query, find person name equals to "Jack" and phone brand equals to "HuaWei".

public List<Phone> findAll(SearchRequest request) {
    Specification<Phone> specification = Specifications.<Phone>and()
        .eq(StringUtils.isNotBlank(request.getBrand()), "brand", "HuaWei")
        .eq(StringUtils.isNotBlank(request.getPersonName()), "person.name", "Jack")
        .build();

    return phoneRepository.findAll(specification);
}

@ManyToMany association query, find person age between 10 and 35, live in "Chengdu" street.

public List<Phone> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
        .between("age", 10, 35)
        .eq(StringUtils.isNotBlank(jack.getName()), "addresses.street", "Chengdu")
        .build();

    return phoneRepository.findAll(specification);
}

Custom Specification

You can custom specification to do the @ManyToOne and @ManyToMany as well.

@ManyToOne association query, find person name equals to "Jack" and phone brand equals to "HuaWei".

Test: PredicateTest.java

public List<Phone> findAll(SearchRequest request) {
    Specification<Phone> specification = Specifications.<Phone>and()
        .eq(StringUtils.isNotBlank(request.getBrand()), "brand", "HuaWei")
        .predicate(StringUtils.isNotBlank(request.getPersonName()), (root, query, cb) -> {
            Path<Person> person = root.get("person");
            return cb.equal(person.get("name"), "Jack");
        })
        .build();

    return phoneRepository.findAll(specification);
}

@ManyToMany association query, find person age between 10 and 35, live in "Chengdu" street.

Test: PredicateTest.java

public List<Phone> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
        .between("age", 10, 35)
        .predicate(StringUtils.isNotBlank(jack.getName()), ((root, query, cb) -> {
            Join address = root.join("addresses", JoinType.LEFT);
            return cb.equal(address.get("street"), "Chengdu");
        }))
        .build();

    return phoneRepository.findAll(specification);
}

Sort

Test: SortTest.java

public List<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .eq(StringUtils.isNotBlank(request.getName()), "name", request.getName())
            .gt("age", 18)
            .between("birthday", new Date(), new Date())
            .like("nickName", "%og%")
            .build();

    Sort sort = Sorts.builder()
        .desc(StringUtils.isNotBlank(request.getName()), "name")
        .asc("birthday")
        .build();

    return personRepository.findAll(specification, sort);
}

Pagination

find person by pagination and sort by name desc and birthday asc.

public Page<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .eq(StringUtils.isNotBlank(request.getName()), "name", request.getName())
            .gt("age", 18)
            .between("birthday", new Date(), new Date())
            .like("nickName", "%og%")
            .build();

    Sort sort = Sorts.builder()
        .desc(StringUtils.isNotBlank(request.getName()), "name")
        .asc("birthday")
        .build();

    return personRepository.findAll(specification, new PageRequest(0, 15, sort));
}

Virtual View

Using @org.hibernate.annotations.Subselect to define a virtual view if you don't want a database table view.

There is no difference between a view and a database table for a Hibernate mapping.

Test: VirtualViewTest.java

@Entity
@Immutable
@Subselect("SELECT p.id, p.name, p.age, ic.number " +
           "FROM person p " +
           "LEFT JOIN id_card ic " +
           "ON p.id_card_id=ic.id")
public class PersonIdCard {
    @Id
    private Long id;
    private String name;
    private Integer age;
    private String number;

    // Getters and setters are omitted for brevity
}    
public List<PersonIdCard> findAll(SearchRequest request) {
    Specification<PersonIdCard> specification = Specifications.<PersonIdCard>and()
            .gt(Objects.nonNull(request.getAge()), "age", 18)
            .build();

    return personIdCardRepository.findAll(specification);
}

Projection, GroupBy, Aggregation

Spring Data JPA doesn't support Projection(a little but trick), GroupBy and Aggregation,

furthermore, Projection/GroupBy/Aggregation are often used for complex statistics report, it might seem like overkill to use Hibernate/JPA ORM to solve it.

Alternatively, using virtual view and give a readable/significant class name to against your problem domain may be a better option.

Copyright and license

Copyright ยฉ 2016-2019 Wen Hao

Licensed under Apache License

jpa-spec's People

Contributors

wenhao avatar marcinsoja avatar souvc avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.