14

次のクエリとメソッドがあります

private static final String FIND = "SELECT DISTINCT domain FROM Domain domain LEFT OUTER JOIN FETCH domain.operators LEFT OUTER JOIN FETCH domain.networkCodes WHERE domain.domainId = :domainId";

@Override
public Domain find(Long domainId) {
    Query query = getCurrentSession().createQuery(FIND);
    query.setLong("domainId", domainId);
    return (Domain) query.uniqueResult();
}

Domainとして_

@Entity
@Table
public class Domain {
    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name = "domain_id")
    private Long domainId;

    @Column(nullable = false, unique = true)
    @NotNull
    private String name;

    @Column(nullable = false)
    @NotNull
    @Enumerated(EnumType.STRING)
    private DomainType type;

    @OneToMany(cascade = {
            CascadeType.PERSIST,
            CascadeType.MERGE
    }, fetch = FetchType.EAGER)
    @JoinTable(joinColumns = {
            @JoinColumn(name = "domain_id")
    }, inverseJoinColumns = {
            @JoinColumn(name = "code")
    })
    @NotEmpty
    @Valid // needed to recur because we specify network codes when creating the domain
    private Set<NetworkCode> networkCodes = new HashSet<>();

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(joinColumns = {
            @JoinColumn(name = "parent", referencedColumnName = "domain_id")
    }, inverseJoinColumns = {
            @JoinColumn(name = "child", referencedColumnName = "domain_id")
    })
    private Set<Domain> operators = new HashSet<>();
    // more
}

Set<NetworkCode>この 1 つのクエリでand > 関係がフェッチされると思いますSet<Domainが、そうではありません。I クエリに 2 つの演算子があるとしDomainます。Hibernate は 1 + 2 * 2 = 5 クエリを実行します。

Hibernate: select distinct domain0_.domain_id as domain1_1_0_, domain2_.domain_id as domain1_1_1_, networkcod4_.code as code2_2_, domain0_.name as name1_0_, domain0_.type as type1_0_, domain2_.name as name1_1_, domain2_.type as type1_1_, operators1_.parent as parent1_0__, operators1_.child as child4_0__, networkcod3_.domain_id as domain1_1_1__, networkcod3_.code as code5_1__ from domain domain0_ left outer join domain_operators operators1_ on domain0_.domain_id=operators1_.parent left outer join domain domain2_ on operators1_.child=domain2_.domain_id inner join domain_network_codes networkcod3_ on domain0_.domain_id=networkcod3_.domain_id inner join network_code networkcod4_ on networkcod3_.code=networkcod4_.code where domain0_.domain_id=?
Hibernate: select operators0_.parent as parent1_1_, operators0_.child as child4_1_, domain1_.domain_id as domain1_1_0_, domain1_.name as name1_0_, domain1_.type as type1_0_ from domain_operators operators0_ inner join domain domain1_ on operators0_.child=domain1_.domain_id where operators0_.parent=?
Hibernate: select networkcod0_.domain_id as domain1_1_1_, networkcod0_.code as code5_1_, networkcod1_.code as code2_0_ from domain_network_codes networkcod0_ inner join network_code networkcod1_ on networkcod0_.code=networkcod1_.code where networkcod0_.domain_id=?
Hibernate: select operators0_.parent as parent1_1_, operators0_.child as child4_1_, domain1_.domain_id as domain1_1_0_, domain1_.name as name1_0_, domain1_.type as type1_0_ from domain_operators operators0_ inner join domain domain1_ on operators0_.child=domain1_.domain_id where operators0_.parent=?
Hibernate: select networkcod0_.domain_id as domain1_1_1_, networkcod0_.code as code5_1_, networkcod1_.code as code2_0_ from domain_network_codes networkcod0_ inner join network_code networkcod1_ on networkcod0_.code=networkcod1_.code where networkcod0_.domain_id=?

Domainこれは、オペレーター要素を結合しているためだと推測していますが、それらは自分自身を結合する必要があります。

両方を実行できる実行可能な HQL クエリはありますか?

4

7 に答える 7

14

ツリーに 2 つのレベルしかないことがわかっている場合、1 つ深いレベルに参加することを考えたことはありますか? 以下のようなものですか?

SELECT DISTINCT domain FROM Domain domain 
  LEFT OUTER JOIN FETCH domain.operators operators1 
  LEFT OUTER JOIN FETCH domain.networkCodes 
  LEFT OUTER JOIN FETCH operators1.operators operators2 
  LEFT OUTER JOIN FETCH operators1.networkCodes
WHERE domain.domainId = :domainId
于 2013-10-09T09:47:55.727 に答える
4

関連付けを EAGER とマークしました。そのため、クエリで何を実行しても、Hibernate は関連付けられたすべてのドメインと、読み込まれたドメインのネットワーク コードを読み込みます。そして、すべてのコレクションの読み込みが空のコレクションまたは既に読み込まれたエンティティを返すまで、追加のドメインのドメインとネットワーク コードなどを読み込みます。

これを避けるには、コレクションを遅延させます (デフォルトのように)。次に、ドメインをそのオペレーターとそのネットワークコードとともにロードすると、それがロードされます。

于 2013-10-08T20:36:05.913 に答える
2

EAGER マッピングは、クエリに Criteria API を使用する場合にのみ、Hibernate によって自動的に考慮されます。

HQL を使用する場合は、手動で FETCH キーワードを JOIN に追加して、Hibernate に最初のクエリに関係を含めさせ、後続のクエリを回避させる必要があります。

これは Hibernate 固有のものであり、他の ORM では異なる動作をする可能性があります。

少し異なる角度については、この質問/回答を参照してください。

于 2013-10-16T07:32:35.313 に答える
1

それほど文書化されていませんが、設定しようとしましたFetchModeか? これは、Criteria API を使用するか、リレーション定義で使用してdomainCriteria.setFetchMode("operators", JOIN)行うことができます。@Fetch(JOIN)

アノテーション (およびそのように見えるアノテーションのみ) を使用すると、フェッチ モードを設定することもできます。これによりSUBSELECT、少なくとも Hibernate が最大 3 つのクエリを実行するように制限する必要があります。データセットがわからないので、これらのテーブルに対する大きな脂肪結合はあまり健康的ではないように思われるため、これが適切な方法であると思います。自分で考えてみるのが一番だと思います...

于 2013-10-09T10:35:00.370 に答える
0

私の最初の観察は、結合を積極的にロードする必要があるとマッピングが示している場合、結合を含む HQL クエリを記述する必要がないということです。

ただし、結合を使用したくない場合は、サブ選択としてフェッチ戦略を使用するように Hibernate に指示できます。

Hibernate は、指定されたマッピングに基づいて起動時にオブジェクトをロードするための SQL クエリを生成し、それをキャッシュします。ただし、あなたの場合、 self および 任意の depthとの1対多のネストされた関係があるため、休止状態が前にSQLを正しく熱心に取得することを決定することはできないようです。そのため、実行時にクエリを実行する親ドメインの深さに応じて、複数の結合クエリを送信する必要があります。

私には、あなたの場合、HQL と結果の SQL/('s) が 1 対 1 の対応関係を持つことができると考えているように見えますが、これは真実ではありません。HQL を使用してオブジェクトを照会すると、orm はそのオブジェクトとその関係 (eager/lazy) をマッピングに基づいてロードする方法を決定するか、実行時に指定することもできます (たとえば、マッピングの遅延関連付けはクエリ API によってオーバーライドできます)。ただし、その逆ではありません)。orm に何をロードするか (私のマーキングeager または lazy ) と熱心にロードする方法 (join / sub select のいずれかを使用) を伝えることができます。

アップデート

ドメインモデルで次のクエリを実行すると

SELECT DISTINCT domain FROM Domain domain LEFT OUTER JOIN FETCH domain.operators LEFT OUTER JOIN FETCH domain.networkCodes WHERE domain.domainId = :domainId";

networkCode コレクションと operator コレクションがインスタンス PersistentSet (これは Hibernate ラッパー) であり、両方とも初期化されたプロパティが true に設定されていることがわかります。また、基礎となるセッション コンテキストでは、ドメインと演算子がリストされたドメインを確認できます。では、熱心にロードされていないと思われる理由は何ですか?

これは私のドメインがどのように見えるかです

@Entity
@Table
public class Domain {
    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name = "domain_id")
    private Long domainId;

    @Column(nullable = false, unique = true)   
    private String name;

    @Column(nullable = false)    
    @Enumerated(EnumType.STRING)
    private DomainType type;

    @OneToMany(mappedBy = "domain",cascade = {
            CascadeType.PERSIST,
            CascadeType.MERGE
    }, fetch = FetchType.EAGER)   
    private Set<NetworkCode> networkCodes = new HashSet<NetworkCode>();

    @ManyToMany(mappedBy="parent",fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    private Set<Domain> operators = new HashSet<Domain>();
    // more

    @ManyToOne  
    private Domain parent;

    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


public DomainType getType() {
        return type;
    }

    public void setType(DomainType type) {
        this.type = type;
    }


    public Set<Domain> getOperators() {
        return operators;
    }


    public Long getDomainId() {
        return domainId;
    }


    public void setDomainId(Long domainId) {
        this.domainId = domainId;
    }


    public void setOperators(Set<Domain> operators) {
        this.operators = operators;
    }

    public void addDomain(Domain domain){
        getOperators().add(domain);
        domain.setParent(this);
    }


    public Domain getParent() {
        return parent;
    }


    public void setParent(Domain parent) {
        this.parent = parent;
    }

    public void addNetworkCode(NetworkCode netWorkCode){
        getNetworkCodes().add(netWorkCode);
        netWorkCode.setDomain(this);
    }

ここに画像の説明を入力

于 2013-10-13T08:47:42.260 に答える