Hackernoon logoDependencies, Entity Classes, and Configuration for Jinq to Create Database Queries in Java by@yaf

Dependencies, Entity Classes, and Configuration for Jinq to Create Database Queries in Java

Fedor Yaremenko Hacker Noon profile picture

@yafFedor Yaremenko

9+ years Java developer

Jinq is a library that provides support for database queries in Java. It is inspired by .NET’s LINQ. A developer can use Java Stream API, standard functions (e.g.

String#contains
,
Math#abs
), and relational, arithmetic and logical operators (e.g. ==, <, +, /, &&, ==) for filtering data.

List<Book> books = jinqDataProvider.streamAll(entityManager, Book.class)
	.where(book -> book.getPages() > 50 && book.isPublished()).toList();

In this example, the

Book
is not a generated metamodel but a JPA entity class. It looks like magic. Under the hood, Jinq uses lambda serialization and bytecode analysis. Let's start looking at Jinq with a Spring Boot example.

Dependencies

Add the following dependencies in the build.gradle file:

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.jinq:jinq-jpa:1.8.32'

Entity classes

Consider the example with two tables in the database:

books
and
authors
. Add the entity classes:

@Entity(name = "books")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    private boolean published;

    private Integer pages;

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

    // getters and setters
}
@Entity(name = "authors")
public class Author {
  
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
  
    private String firstName;
  
    private String lastName;
  
    @OneToMany(mappedBy = "author", cascade = CascadeType.ALL, orphanRemoval = true)
    @OrderBy("id")
    private final Set<Book> books = new LinkedHashSet<>();
    
    // getters and setters
}

Configuration and Helper

We need to create a

JinqJPAStreamProvider
bean for using Jinq.

@Configuration
public class JinqProviderConfiguration {

    @Bean
    JinqJPAStreamProvider jinqDataProvider(EntityManagerFactory emf) {
        return new JinqJPAStreamProvider(emf);
    }

}

We need to use the

JinqJPAStreamProvider#streamAll
method for creating streams. Let's add a helper class.

@Component
public class JinqHelper {
  
    @PersistenceContext
    private EntityManager entityManager;
  
    private final JinqJPAStreamProvider jinqDataProvider;
  
    public JinqHelper(JinqJPAStreamProvider jinqDataProvider) {
        this.jinqDataProvider = jinqDataProvider;
    }
  
    public <T> JPAJinqStream<T> stream(Class<T> clazz) {
        return jinqDataProvider.streamAll(entityManager, clazz);
    }
  
}

Now we are ready to query the database.

Query Examples

We can use the

count
method to get the number of all authors.

long authorsCount = jinqHelper.stream(Author.class).count();

Let's retrieve all published books that have more than 50 pages.

List<Book> books = jinqHelper.stream(Book.class).where(book ->
    book.getPages() > 50 && book.isPublished()).toList();

If we want to read-only specific columns, we can use the

select
method and the
Pair
or
Tuple3
, ...,
Tuple8
classes in the
org.jinq.tuples
package.

List<Pair<String, String>> allAuthors = jinqHelper.stream(Author.class)
        .where(author -> author.getFirstName().equals("Simon"))
        .select(author -> new Pair<>(author.getFirstName(), author.getLastName()))
        .toList();

for (Pair<String, String> author : allAuthors) {
    String firstName = author.getOne();
    String lastName = author.getTwo();
    // ...
}

Jinq provides aggregation methods.

Double avgPages = jinqHelper.stream(Book.class).avg(Book::getPages);

We can use the

joinList
method to perform join-queries. We also use the
Pair
class in the following example

List<Pair<Author, Book>> joinedList = jinqHelper.stream(Author.class)
        .where(author -> author.getFirstName().equals("Simon"))
        .joinList(Author::getBooks)
        .where(pair -> pair.getTwo().isPublished())
        .toList();

Advanced Features

Jinq also provides support for grouping, sorting, different types of joins, subqueries, registering your own functions, and other useful features.

Conclusion

Jinq provides a convenient and natural way to build type-safe database queries. It is easier to use than JPA 1 Criteria API and does not require code generation as Query DSL or JPA 2 metamodel.

Tags

Join Hacker Noon

Create your free account to unlock your custom reading experience.