QurakusでMultiple Persistance Unitsを使う
前回書いた図みたいに、複数のデータソースにアクセスできることを目指したとき、過去にそれが試みてできなかったことを思い出した。
具体的には、どのようにすれば、複数のHibernateの接続先を定義できるのかがよくわからず諦めていた。
が、実は1.8.0からできるようになっている。
Quarkus 1.8 released - Multiple Persistence Units, Micrometer, jbang, GraalVM 20.2
自分がやりたかったことは "Multiple Persistance Units" と呼ぶらしい。
必要な設定は次の3つ。
- EntityManagerのクラスのInject時に @PersistenceUnit として他の Persistence Unitと区別可能なデータソースのnameを指定する
- application.propertiesに PersistanceUnit用のデータソースを指定する
- 使用するEntityを、Persistance Unit毎にパッケージ分けする
大体のことはここに書いてある。
Quarkus - Using Hibernate ORM and JPA
記載例としては、
1.の例:
1つのPersistance Unitしか使わない場合には不要だった@PersistenceUnitが追加されている。
ここで指定している名前と2.に書くPersistence Unitの名前を合致させる必要がある。
@Inject
@PersistenceUnit("dummy1")
EntityManager em;
2.の例:
わかりやすさのために自分はdummy1で全て統一してしまっているが、ここには3つの話が載っていると思う。
# dummy1
quarkus.datasource."dummy1".db-kind=postgresql
quarkus.datasource."dummy1".username=postgres
quarkus.datasource."dummy1".password=postgres
quarkus.datasource."dummy1".jdbc.url=jdbc:postgresql://localhost:15432/postgres
quarkus.hibernate-orm."dummy1".database.generation=drop-and-create
quarkus.hibernate-orm."dummy1".datasource=dummy1
quarkus.hibernate-orm."dummy1".packages=dev.tkhm.graphbff.infrastructure.dummy1
読みづらいけど、次のように理解している。
①の青い囲み左の部分はPersistence Unitが探しにくるKeyになっている。
②の青い囲み右の部分はPersistence Unitと紐づけるEntityが入ったパッケージの指定をしている。(~infrastructure.dummy1パッケージの下に作ったEntityは"dummy1"Persistence Unitと紐づく)
③の緑の線の部分はPersistence UnitとDataSourceを紐づけている。
3.の例:
dummy1とdummy2、それぞれ別のPersistence Unitを使う場合にこのようにする。2.の例と平仄を合わせる必要がある。
infrastructure
├── dummy1
│ └── Dummy1OrmEntity.java
└── dummy2
└── Dummy2OrmEntity.java
これができることがわかったので、本格的にQuarkusでのGraphQLをBFFとして使う、ということがそれほどの難易度なく実現できそうだと確認できた。
ついでに検索で引っかかったので次の質問にも回答しておいた。
Quarkus: EntityManager injection with multiple datasources - Stack Overflow
ところで、ドメインモデルとしてのEntityとORMのためのEntity、持つ値が被る箇所も多くて困るんだけど、これどうにかならないかなあ。
ドメイン側のEntityをORMのためのEntity側で継承して使って、最後は親クラスにアップキャストして返せばいいかと思ってやってみたんだけど、その方法だとORMのEntityがTypedQueryでクラス不一致を宣告されてしまう......。多分 @Entity のアノテーションの仕組み、内部的な振る舞いを理解しないとできないのかも。
とりあえずは愚直にORM側のEntityをドメイン側のEntityに変換することで対応しているけれど、通常どうするんだろう。小さな悩みの種。
Discussion