FleaJPAQueryに基づくJPAサブテーブルクエリの実現
この記事ではEclipseLinkのJPA実装を使用しています。FleaJPAQueryへのアクセスと使用については、他のブログ投稿を参照してください。
まず、JPAサブテーブルクエリを実装するために何をする必要があるかについて説明しましょう。
- サブテーブルルールの定義(つまり、メインテーブルからサブテーブルへの変換の実現)
- サブテーブルクエリの実装(つまり、JPA標準化クエリコンポーネントは、サブテーブルルールに従って特定のサブテーブルをクエリします)
JPA標準化クエリ
JPAでは、エンティティに対応するテーブルは次のアノテーションによって定義されます。
@Entity
@Table(name = "flea_login_log")
上記のように、エンティティクラスは実際には1つのテーブル名にのみ対応し、サブテーブルクエリはここだけでは実現できません。
したがって、テーブルを分割することは不可能であるため、クエリの最後のテーブル名が使用されたアノテーションによって定義されたテーブル名である必要があることを確認できるため、戻ってそのオブジェクトでテーブル名がいつ使用されるかを確認することにします。
以下は、デバッグプロセスの発見です:
com.huazie.frame.db.jpa.common.FleaJPAQuery
/**
* <p> Flea JPA查询对象池获取之后,一定要调用该方法进行初始化 </p>
*
* @param entityManager JPA中用于增删改查的接口
* @param sourceClazz 实体类类对象
* @param resultClazz 操作结果类类对象
* @since 1.0.0
*/
public void init(EntityManager entityManager, Class sourceClazz, Class resultClazz) {
this.entityManager = entityManager;
this.sourceClazz = sourceClazz;
this.resultClazz = resultClazz;
// 从持久化接口中获取标准化生成器
criteriaBuilder = entityManager.getCriteriaBuilder();
// 通过标准化生成器 获取 标准化查询对象
if (ObjectUtils.isEmpty(resultClazz)) {
// 行记录查询结果
criteriaQuery = criteriaBuilder.createQuery(sourceClazz);
} else {
// 单个查询结果
criteriaQuery = criteriaBuilder.createQuery(resultClazz);
}
// 通过标准化查询对象,获取根SQL表达式对象
root = criteriaQuery.from(sourceClazz);
}
次の2つの図は、ルートSQL式オブジェクトRootのデバッグビューです。DatabaseTableオブジェクトには実際のテーブル名が格納されていることがわかります。
テーブル名の実際の相関関係が見つかったので、次の焦点は、JPA標準化クエリを使用するプロセスでクエリテーブル名を動的に変更する方法です。私たちがしなければならない上記のことに対する解決策を以下に示します。
サブテーブルルールの定義
エンティティクラスで定義されたテーブル名は、メインテーブル名として理解できます。サブテーブル名の命名規則を最初に決定する必要があり、次の構成が定義されています。
<?xml version="1.0" encoding="UTF-8"?>
<tables>
<!-- 定义分表配置
name : 分表对应的主表名
exp : 分表名表达式 (FLEA_TABLE_NAME)_(列名大写)_(列名大写)
-->
<table name="flea_login_log" exp="(FLEA_TABLE_NAME)_(CREATE_DATE)" desc="Flea登录日志表分表规则">
<splits>
<!-- 定义分表后缀
key : 分表类型关键字 (可查看 com.huazie.frame.db.common.table.split.TableSplitEnum )
column : 分表属性列字段名
implClass : 分表后缀转换实现类
-->
<split key="yyyymm" column="create_date" implClass="com.huazie.frame.db.common.table.split.impl.YYYYMMTableSplitImpl"/>
</splits>
</table>
</tables>
テーブル分割ルールに関連する実装コードについては、GitHubに移動してTableSplitHelperを表示できます。
サブテーブルクエリの実装
上記のサブテーブルルールの定義では、サブテーブル名式expがメインテーブル名とサブテーブルフィールドで構成されており、サブテーブルフィールドの変換実装ルールがsplitによって定義されていることがわかります。
@Override
public void handle(CriteriaQuery criteriaQuery, Object entity) throws Exception {
if (ObjectUtils.isEmpty(criteriaQuery) || ObjectUtils.isEmpty(entity)) {
return;
}
// 获取分表信息(包括主表名 和 分表名 【如果存在分表返回】)
SplitTable splitTable = EntityUtils.getSplitTable(entity);
// 存在分表,需要查询指定分表
if (StringUtils.isNotBlank(splitTable.getSplitTableName())) {
Set<Root<?>> roots = criteriaQuery.getRoots();
if (CollectionUtils.isNotEmpty(roots)) {
// 重新设置 查询的分表表名
((EntityTypeImpl<?>) roots.toArray(new Root<?>[0])[0].getModel()).getDescriptor().setTableName(splitTable.getSplitTableName());
}
}
}
JPAサブテーブルクエリ関連のコードをGitHubに移動して、FleaJPAQueryとEclipseLinkTableSplitHandlerを表示できます。セルフテストクラスはAuthTestで表示できます。