概要
Ebeanは、クエリBean
を生成することにより、タイプセーフなクエリを構築するメカニズムを提供します。クエリBean
とタイプセーフなクエリ構築のために採用された設計/アプローチは、最大限の可読性を重視しており、それをJava(プロパティのサポートがない)で実現するためには、AOPを使用してクエリBean
を拡張する必要がありました。 AOP拡張は、以下を介して行うことができます。
IntelliJ IDEA Plugin
- 開発中の使用に最適javaagent
- 開発中は「OK」、本番環境へのデプロイに適しているmaven plugin
- 本番環境へのデプロイに適している
推奨事項
開発中は、IntelliJ IDEA Plugin
を使用することを推奨します。これは、テストなどを実行する際にjavaagent
を指定するのに比べて、非常に簡単に使用できるためです。
デプロイ/本番環境では、javaagent
またはmaven plugin
を使用できます。
メリット
モデルの変更
エンティティBeanモデルが変更されると、クエリBeanが再生成されます。モデルの変更によってクエリが壊れた場合、コンパイルエラー(ランタイムエラーではなく)が発生するため、モデルの破壊的な変更を簡単かつ早期に検出できます。
型付きバインド値
クエリBeanを使用すると、特定のプロパティに使用されるバインド値は、プロパティの型と互換性がある必要があります。たとえば、型がTimestampであるプロパティにString値をバインドできます。
開発スピード
クエリBeanを使用すると、IDEのオートコンプリートを使用してクエリを作成できます。クエリを構築するときにモデルを確認する必要はありません。これにより、開発が少し速く、安全に、そして楽しくなります!
長期的なメンテナンス
アプリケーションが大きくなり古くなるにつれて、強力な型のクエリBeanを使用すると、モデルにあまり詳しくない新しい開発者をガイドするのに役立つため、メンテナンスが容易になります。また、文字列ベースのクエリと比較して、コンパイル時の型チェックにより、大規模なアプリケーションでのモデル変更のリスクが大幅に軽減されます。
例
例
List<Customer> customers =
new QCustomer()
.id.greaterThan(12)
.name.startsWith("Rob")
.findList();
例:ネストされたor()とand()
次の例には、ネストされたand()
を含むor()
が含まれています。
List<Customer> customers
= new QCustomer()
.billingAddress.city.equalTo("Auckland")
.version.between(1,100)
.billingAddress.country.equalTo(nz)
.registered.before(new Date())
.or()
.id.greaterThan(1)
.and()
.name.icontains("Jim")
.inactive.isTrue()
.endAnd()
.endOr()
.orderBy()
.name.asc()
.id.desc()
.findList();
例:filterMany
filterManyは、関連付けられたOneToManyまたはManyToManyリレーションシップの返されたオブジェクトをフィルタリングする機能を提供します。
たとえば、顧客には多くの注文があり、特定のユースケースでは顧客を見つけて、最近の新しい注文のみを取得したいとします。顧客の注文(OneToMany)を取得したいが、それらの注文をフィルタリングして「最近の新しい注文」のみを含めたいとします。
Date oneWeekAgo = ...
// Use QOrder to create an expression list ...
// .. use this expression list to then filter orders
ExpressionList<Order> recentNewOrders = new QOrder()
.orderDate.after(oneWeekAgo)
.status.eq(Order.Status.NEW)
.getExpressionList();
List<Customer> customers = new QCustomer()
.name.ilike("Rob")
// filter the orders (not customers)
.orders.filterMany(recentNewOrders)
.findList();
例:select()とfetch()
alias()
メソッドを使用して、select()
およびfetch()
のプロパティを指定するために使用できるクエリBean
の共有インスタンスを取得します。
alias()
メソッドによって返されるクエリBeanの「エイリアス」インスタンスには、関連付けられた基になるクエリがなく、select()
およびfetch()
にプロパティを提供するためにのみ使用できることに注意してください。
// special 'alias' instances of query beans
// used to supply properties to the select() and fetch()
QCustomer cus = QCustomer.alias();
QContact con = QContact.alias();
List<Customer> customers = new QCustomer()
// query tuning
.select(cus.name, cus.inactive)
.contacts.fetch(con.email, con.firstName)
// predicates
.name.ilike("Rob")
.findList();
// special 'alias' instances of query beans
// used to supply properties to the select() and fetch()
QContact con = QContact.alias();
QCustomer cus = QCustomer.alias();
QProduct pro = QProduct.alias();
Customer customer =
Customer.find.where()
// manual query tuning
.select(cus.name, cus.registered)
.orders.fetchAll()
.orders.details.product.fetch(pro.name)
.contacts.fetch(con.firstName)
// predicates
.id.eq(12)
.findOne();
APT / KAPT (クエリBeanの生成)
Java
クエリBeanを生成するには、io.ebean:querybean-generator Javaアノテーションプロセッサを使用し、Kotlin
クエリBeanを生成するには、io.ebean:kotlin-querybean-generatorを使用します。
Mavenでの生成
mavenを使用してクエリBeanを生成する方法の詳細については、docs / getting-started / mavenを参照してください。
Gradleでの生成
gradleを使用してクエリBeanを生成する方法の詳細については、docs / getting-started / gradleを参照してください。
拡張
バージョン12.1.8より前は、src/main/resources/ebean.mf
マニフェストファイルを編集して、クエリBean用に拡張する必要があるパッケージのquerybean-packages
を指定する必要がありました。これは、12.1.8以降は不要になりました。
手動生成
(javacアノテーション処理を介さずに)コードを実行してクエリBeanを生成するメカニズムがあります。これは、エンティティBeanに変更があるたびにこのプロセスを再実行する必要があるという意味で手動です(Javaアノテーションプロセッサでは、コンパイルごとに自動的に更新されます)。
<dependency>
<groupId>io.ebean.tools</groupId>
<artifactId>finder-generator</artifactId>
<version>12.1.1</version>
</dependency>
クエリBean
を生成するには、以下のようなコードをsrc/test
に追加します。ジェネレータは、ASM
ライブラリを使用してコンパイル済みの.class
エンティティBeanを読み取ります。次に、このメタデータを使用して、クエリBean
のJavaソースを生成します。
このアプローチをjavac
アノテーション処理を使用する代わりに、javacは必要ないことを意味します。任意のJVM言語を使用してエンティティBeanを記述/コンパイルできます(たとえば、Scala
とSBT)。
このアプローチの要件は、エンティティBeanが.classファイルとしてコンパイルされ、GeneratorConfig
がクラスの場所、ソースコードの出力先、およびエンティティBeanを含むパッケージを認識するように構成されていることです。
package main;
import org.avaje.ebean.typequery.generator.Generator;
import org.avaje.ebean.typequery.generator.GeneratorConfig;
import java.io.IOException;
/**
* Generate type query beans for each entity bean.
*/
public class MainQueryBeanGenerator {
public static void main(String[] args) throws IOException {
GeneratorConfig config = new GeneratorConfig();
//config.setClassesDirectory("./target/classes");
//config.setDestDirectory("./src/main/java");
//config.setDestResourceDirectory("./src/main/resources");
config.setEntityBeanPackage("org.example.domain");
//config.setDestPackage("org.example.domain.query");
//config.setOverwriteExistingFinders(true);
Generator generator = new Generator(config);
generator.generateQueryBeans();
// Additionally generate 'finder's
//generator.generateFinders();
//generator.modifyEntityBeansAddFinderField();
}
}