SpringによるJinqの紹介
1前書き
Jinq
は、Javaでデータベースを照会するための直感的で便利なアプローチを提供します。このチュートリアルでは、Jinqを使用するようにSpringプロジェクトを設定する方法と、簡単な例で説明されているその機能のいくつかを探ります。
2 Mavenの依存関係
Jinq依存関係
を追加する必要があります。]
pom.xml
ファイル
<dependency>
<groupId>org.jinq</groupId>
<artifactId>jinq-jpa</artifactId>
<version>1.8.22</version>
</dependency>
Springにはhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework%22%20AND%20a%3A%22spring-orm%22[the Springを追加します
pom.xml
ファイル内のORM依存関係]
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.0.3.RELEASE</version>
</dependency>
最後に、テスト用にH2インメモリデータベースを使用しますので、https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22com.h2database%22%20ANDも追加しましょう%20a%3A%22h2%22
pom.xml
ファイルへの[この依存関係]:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
</dependency>
3 Jinqを理解する
Jinqは、内部的に
Java Stream API
モデル別に車を絞り込む例を見てみましょう。
jinqDataProvider.streamAll(entityManager, Car.class)
.where(c -> c.getModel().equals(model))
.toList();
-
Jinqは上記のコードスニペットを効率的な方法でSQLクエリに変換します。
select c.** from car c where c.model=?
-
クエリの記述にプレーンテキストを使用せず、代わりにタイプセーフなAPIを使用するので、この方法ではエラーが発生しにくくなります。
さらに、Jinqは一般的で読みやすい式を使用することで開発のスピードアップを図っています。
それでも、次に説明するように、使用できる種類や操作の数には制限があります。
3.1. 制限事項
-
JinqはJPAの基本型とSQL関数の具体的なリストのみをサポートしています** すべてのオブジェクトとメソッドをJPAデータ型とSQL関数にマッピングすることにより、ラムダ操作をネイティブSQLクエリに変換します。
したがって、このツールがすべてのカスタム型または型のすべてのメソッドを変換することは期待できません。
3.2. サポートされているデータ型
サポートされているデータ型とサポートされているメソッドを見てみましょう。
-
String
–
equals()
、
compareTo()
メソッドのみ -
プリミティブデータ型 – 算術演算
-
Enums
とカスタムクラス – ==と!=の操作のみをサポート -
java.util.Collection –
contains()
-
Date
API –
equals()
、
before()
、
after()
メソッドのみ -
注:Javaオブジェクトからデータベースオブジェクトへの変換をカスタマイズしたい場合は、
AttributeConverter
の具体的な実装をJinqに登録する必要があります。
4 JinqとSpring
の統合
-
永続コンテキストを取得するには、Jinqではhttps://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html[
EntityManager
]インスタンスが必要です。** このチュートリアルでは、次の簡単な方法を紹介します。 Jinqをhttp://hibernate.org/[休止状態]で提供される
EntityManager
と連携させるための春。
4.1. リポジトリインタフェース
-
Springはエンティティの管理にリポジトリの概念を使用しています** 特定のモデルの
Car
を取得するメソッドがある
CarRepository
インターフェースを見てみましょう。
public interface CarRepository {
Optional<Car> findByModel(String model);
}
4.2. 抽象ベースリポジトリ
次に、すべてのJinq機能を提供するために、** ベースリポジトリが必要です。
public abstract class BaseJinqRepositoryImpl<T> {
@Autowired
private JinqJPAStreamProvider jinqDataProvider;
@PersistenceContext
private EntityManager entityManager;
protected abstract Class<T> entityType();
public JPAJinqStream<T> stream() {
return streamOf(entityType());
}
protected <U> JPAJinqStream<U> streamOf(Class<U> clazz) {
return jinqDataProvider.streamAll(entityManager, clazz);
}
}
4.3. リポジトリの実装
-
今、Jinqに必要なのは
EntityManager
インスタンスとエンティティタイプクラスだけです。
先ほど定義したJinqベースリポジトリを使用した
Car
リポジトリの実装を見てみましょう。
@Repository
public class CarRepositoryImpl
extends BaseJinqRepositoryImpl<Car> implements CarRepository {
@Override
public Optional<Car> findByModel(String model) {
return stream()
.where(c -> c.getModel().equals(model))
.findFirst();
}
@Override
protected Class<Car> entityType() {
return Car.class;
}
}
4.4.
JinqJPAStreamProvider
を配線する
JinqJPAStreamProvider
インスタンスを配線するために、Jinqプロバイダ設定を追加します。
@Configuration
public class JinqProviderConfiguration {
@Bean
@Autowired
JinqJPAStreamProvider jinqProvider(EntityManagerFactory emf) {
return new JinqJPAStreamProvider(emf);
}
}
4.5. Springアプリケーションの設定
最後のステップは、HibernateとJinq設定を使用してSpringアプリケーションを設定することです。
spring.datasource.url=jdbc:h2:~/jinq
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
5問い合わせガイド
-
Jinqは、
selectを使って最終的なSQLクエリをカスタマイズするための直感的なオプションを数多く提供します。ここで、
__joinsなど。これらは、上で紹介したのと同じ制限があります。
5.1. どこで
where
句を使用すると、データコレクションに複数のフィルタを適用できます。
次の例では、モデルと説明で自動車を絞り込みます。
stream()
.where(c -> c.getModel().equals(model)
&& c.getDescription().contains(desc))
.toList();
そしてこれがJinqが翻訳するSQLです:
select c.model, c.description from car c where c.model=? and locate(?, c.description)>0
5.2. 選択
データベースからいくつかの列/フィールドのみを取得したい場合は、
select
句を使用する必要があります。
複数の値をマップするために、Jinqは最大8つの値を持ついくつかの
Tuple
クラスを提供します。
stream()
.select(c -> new Tuple3<>(c.getModel(), c.getYear(), c.getEngine()))
.toList()
そして翻訳されたSQL:
select c.model, c.year, c.engine from car c
5.3. 参加する
-
エンティティが正しくリンクされていれば、Jinqは1対1および多対1の関係を解決することができます。
たとえば、
Car
に製造元エンティティを追加したとします。
@Entity(name = "CAR")
public class Car {
//...
@OneToOne
@JoinColumn(name = "name")
public Manufacturer getManufacturer() {
return manufacturer;
}
}
__Car
sのリストを持つ
Manufacturer__エンティティ
@Entity(name = "MANUFACTURER")
public class Manufacturer {
//...
@OneToMany(mappedBy = "model")
public List<Car> getCars() {
return cars;
}
}
与えられたモデルの
製造元
を取得できるようになりました。
Optional<Manufacturer> manufacturer = stream()
.where(c -> c.getModel().equals(model))
.select(c -> c.getManufacturer())
.findFirst();
予想通り、このシナリオでは
Jinqは内部結合SQL句
を使用します。
select m.name, m.city from car c inner join manufacturer m on c.name=m.name where c.model=?
-
多対多の関係のように、エンティティに対してより複雑な関係を実装するために
join
句をもっと制御する必要がある場合は、
join
メソッドを使用できます。
List<Pair<Manufacturer, Car>> list = streamOf(Manufacturer.class)
.join(m -> JinqStream.from(m.getCars()))
.toList()
最後に、
join
メソッドの代わりに
leftOuterJoin
メソッドを使用して、左外部結合SQL句を使用できます。
5.4. 集計
これまでに紹介した例はすべて、Jinqでクエリの最終結果を返すために
toList
メソッドまたは
findFirst
メソッドのいずれかを使用しています。
これらの方法以外にも、結果を集計するための他の方法にもアクセスできます。
たとえば、
count
メソッドを使用して、具体的なモデルの自動車の総数をデータベースで取得します。
long total = stream()
.where(c -> c.getModel().equals(model))
.count()
そして最後のSQLは期待通りに
count
SQLメソッドを使っています:
select count(c.model) from car c where c.model=?
Jinqは、
sum
、
average
、
min
、
max、
などの集約方法と、異なる集約を組み合わせる** 可能性も提供します。
5.5. ページ付け
データをバッチで読みたい場合は、
limit
と
skip
メソッドを使用できます。
最初の10台の車をスキップして20個の商品だけを取得する例を見てみましょう。
stream()
.skip(10)
.limit(20)
.toList()
そして生成されたSQLは次のとおりです。
select c.** from car c limit ? offset ?
6. 結論
そこに行きます。この記事では、Hibernateを使用してJinqでSpringアプリケーションを設定するためのアプローチについて説明しました(最小限)。
また、Jinqの利点とその主な機能についても簡単に説明しました。
いつものように、ソースはhttps://github.com/eugenp/tutorials/tree/master/spring-jinq[over on GitHub]にあります。