使用 HQL 通过多个映射表进行选择?

Selecting through multiple mapped tables with HQL?

我很难 select 使用 HQL 从给定的 Country 生成 Brand。 我做了一些逆向工程,所以你可以想象我的数据库是如何建模的:

To select the Brand from the right Country I'd have to go through Address as well as their City and State.

就带注释的映射而言,我这样做了:

品牌

@Table(name = "brand")
public class Brand extends BasicModel {

    private String name;
    @OneToMany(targetEntity = Address.class, cascade = CascadeType.ALL,
                fetch = FetchType.LAZY, orphanRemoval = true)
    @JoinTable(name="brand_address",
            joinColumns = { @JoinColumn(name = "brand_id") },
            inverseJoinColumns = { @JoinColumn(name = "address_id") })
    private Set<Address> address;

地址

@Table(name = "address")
public class Address extends BasicModel {

    @NotNull
    @ManyToOne
    private AddressCity city;

AddressCity 映射到 AddressState,后者映射到 AddressCountry,其方式与 AddressCity 映射到 Address.[=42 的方式相同=]

table brand_address 由 Hibernate 自动创建。

现在 和 SQL 我需要加入所有这些 table 才能到达 Country 但是 因为它已经用 Hibernate 注释映射了,我应该如何将 HQL 从给定的 Country 写入 select 和 Brand?

信息:当我创建一个包含一组地址的国家/地区时,table brand_address 被正确填充。

到目前为止有效的方法 只是selecting Brand,Hibernate 将返回所有已填充的对象。我可以通过以下方式做到这一点:

    Query query = session
            .createQuery("from Brand brand " +
                            "where brand.name = :brandName " +
                                "and brand.deleted is null");
    query.setParameter("brandName", brandName);

有了这个,我可以很容易地从其他 Countries 中过滤掉具有该名称的 Brands,但它闻起来不像是最佳做法...

到目前为止还没有用的地方 当我尝试时:

    Query query = session
            .createQuery("from Brand brand " +
                            "where brand.name = :brandName " +
                                "and Address.city.state.country.code = :countryCode " +
                                "and brand.deleted is null");
    query.setParameter("brandName", brandName);
    query.setParameter("countryCode", countryCode);

    Query query = session
            .createQuery("from Brand brand " +
                            "where brand.name = :brandName " +
                                "and AddressCountry.code = :countryCode " +
                                "and brand.deleted is null");
    query.setParameter("brandName", brandName);
    query.setParameter("countryCode", countryCode);

我该如何解决? 有没有办法让我在不在上述查询中编写多个连接的情况下进入 country? 我是否应该 select 一切都按照它已经工作的方式进行,然后将结果过滤回我的 DAO 中?

我一直在网上搜索这个,但只找到关于如何 映射和插入 信息的信息,而不是关于如何编写查询 [=111] =] 通过 tables.

我提前感谢你们这些美丽的人可以通过我的方式发送的任何帮助和建议!

更新 1:我试过添加

left join brand.address as a
with a.city.state.country.code = :countryCode

它导致了一个新的错误:

java.sql.SQLSyntaxErrorException:'on clause'

中的未知列 'addresscit3_.state_id'

具有以下日志:

14:02:43.646 [main] DEBUG org.hibernate.hql.internal.ast.util.JoinProcessor - Using FROM fragment [brand brand0_]
14:02:43.646 [main] DEBUG org.hibernate.hql.internal.ast.util.JoinProcessor - Using FROM fragment [inner join address_state addresssta4_ on addresscit3_.state_id=addresssta4_.id]
14:02:43.646 [main] DEBUG org.hibernate.hql.internal.ast.util.JoinProcessor - Using FROM fragment [inner join address_country addresscou5_ on addresssta4_.country_id=addresscou5_.id]
14:02:43.647 [main] DEBUG org.hibernate.hql.internal.ast.util.JoinProcessor - Using FROM fragment [inner join brand_address addresses1_ on brand0_.id=addresses1_.brand_id inner join address address2_ on addresses1_.address_id=address2_.id and (addresscou5_.code=?)]
14:02:43.647 [main] DEBUG org.hibernate.hql.internal.ast.util.JoinProcessor - Using FROM fragment [inner join address_city addresscit3_ on address2_.city_id=addresscit3_.id]
14:02:43.647 [main] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - select >> end [level=1, statement=select]

更新 2:解决方案

按照@guillaume 的建议使用 with 键确实以连接顺序似乎放错了位置的方式更改了错误...我的一个朋友建议使用 join fetch 因为懒惰加载并调整查询,直到一切就绪,如下所示:

    .createQuery("from Brand brand " +
                    "join fetch brand.addresses as a " +
                        "where brand.name = :brandName " +
                        "and a.city.state.country.code = :countryCode " +
                        "and brand.deleted is null");

条件 Address.city.state.country.code = :countryCode 没有意义,因为地址实际上是一个 Set 地址(将其命名为地址可能会更清楚)。

试试这个:

from Brand brand
left join brand.address as a
with a.city.state.country.code = :countryCode

您不需要“加入获取”您的品牌实体,您的查询也应该使用“加入”。

勾选这个What is the difference between JOIN and JOIN FETCH when using JPA and Hibernate