web-dev-qa-db-ja.com

複数のテーブルを結合するHibernate CriteriaBuilder

Hibernate criteriabuilderを使用して4つのテーブルを結合しようとしています。
以下はそれぞれ表です。 `

@Entity
public class BuildDetails {
    @Id
    private long id;
    @Column
    private String buildNumber; 
    @Column
    private String buildDuration;
    @Column
    private String projectName;

}   

@Entity
public class CodeQualityDetails{
    @Id
    private long id;
    @Column
    private String codeHealth;
    @ManyToOne
    private BuildDetails build; //columnName=buildNum
}

@Entity
public class DeploymentDetails{
    @Id
    private Long id;
    @Column
    private String deployedEnv;
    @ManyToOne
    private BuildDetails build; //columnName=buildNum
}

@Entity
public class TestDetails{
    @Id
    private Long id;
    @Column
    private String testStatus;
    @ManyToOne
    private BuildDetails build; //columnName=buildNum
}


これらの4つのテーブルで、MySQLに対して以下のsqlスクリプトを実行します。

SELECT b.buildNumber, b.buildDuration,
       c.codeHealth, d.deployedEnv, t.testStatus
FROM BuildDetails b
INNER JOIN CodeQualityDetails c ON b.buildNumber=c.buildNum
INNER JOIN DeploymentDetails d ON b.buildNumber=d.buildNum
INNER JOIN TestDetails t ON b.buildNumber=t.buildNum
WHERE b.buildNumber='1.0.0.1' AND
      b.projectName='Tera'

それでは、Hibernate CriteriaBuilderを使用してこれをどのように実現できますか?助けてください...

前もって感謝します.......

14
ktgirish
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(/* Your combined target type, e.g. MyQueriedBuildDetails.class, containing buildNumber, duration, code health, etc.*/);

Root<BuildDetails> buildDetailsTable = query.from(BuildDetails.class);
Join<BuildDetails, CopyQualityDetails> qualityJoin = buildDetailsTable.join(CopyQualityDetails_.build, JoinType.INNER);
Join<BuildDetails, DeploymentDetails> deploymentJoin = buildDetailsTable.join(DeploymentDetails_.build, JoinType.INNER);
Join<BuildDetails, TestDetails> testJoin = buildDetailsTable.join(TestDetails_.build, JoinType.INNER);

List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(BuildDetails_.buildNumber, "1.0.0.1"));
predicates.add(cb.equal(BuildDetails_.projectName, "Tera"));

query.multiselect(buildDetails.get(BuildDetails_.buildNumber),
                  buildDetails.get(BuildDetails_.buildDuration),
                  qualityJoin.get(CodeQualityDetails_.codeHealth),
                  deploymentJoin.get(DeploymentDetails_.deployedEnv),
                  testJoin.get(TestDetails_.testStatus));
query.where(predicates.stream().toArray(Predicate[]::new));

TypedQuery<MyQueriedBuildDetails> typedQuery = entityManager.createQuery(query);

List<MyQueriedBuildDetails> resultList = typedQuery.getResultList();

クラス用のJPAメタモデルを作成したと想定しています。メタモデルがない場合、または単に使用したくない場合は、BuildDetails_.buildNumberと残りをStringなどの実際の列名に置き換えてください。 "buildNumber"

答えをテストすることはできませんでした(エディターのサポートなしで作成していました)が、少なくともクエリを構築するために知っておく必要があるすべてのものが含まれている必要があります。

メタモデルを構築する方法は? hibernate tooling をご覧ください(または JPA 2.0メタモデルを生成する方法? を参照してください)。 Mavenを使用している場合、ビルドクラスパスにhibernate-jpamodelgen- dependencyを追加するだけで簡単にできます。私はそのようなプロジェクトを現在利用できないので、以下についてはよくわかりません(そのため、一粒の塩でそれを取る)。以下を依存関係として追加するだけで十分な場合があります。

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-jpamodelgen</artifactId>
  <version>5.3.7.Final</version>
  <scope>provided</scope> <!-- this might ensure that you do not package it, but that it is otherwise available; untested now, but I think I used it that way in the past -->
</dependency>
13
Roland