在 Hibernate 中使用连接表初始化多对多关联

Posted

技术标签:

【中文标题】在 Hibernate 中使用连接表初始化多对多关联【英文标题】:Initializing many-to-many association in Hibernate with join table 【发布时间】:2015-04-11 17:07:04 【问题描述】:

我有一个Company 实体,我通过 Hibernate 的 JPQL 查询获取该实体。该实体与Keyword 实体具有多对多关联。由于连接表有一个附加列is_active,因此该表已映射到CompanyKeyword 实体。所以关联是这样的:

公司 关键字

现在,来自Company 实体的关联是惰性的,它不是由我的 JPQL 查询初始化的,因为我想避免产生笛卡尔积性能问题。这就是为什么我想在运行 JPQL 查询之后初始化关联 ,例如像这样:

@Service
class CompanyServiceImpl implements CompanyService 
    @Autowired
    private CompanyRepository companyRepository;

    @Transactional
    public Company findOne(int companyId) 
        Company company = this.companyRepository.findOneWithSomeCustomQuery(companyId);
        Hibernate.initialize(company.companyKeywords());
        return company;
    

对于“正常”的多对多关联,这会很有效,因为所有关联的实体都将在单个查询中获取。然而,由于我在CompanyKeyword 之间有一个实体,所以Hibernate 只会初始化关联的第一部分,即从CompanyCompanyKeyword,而不是从CompanyKeywordKeyword。我希望这是有道理的。我正在寻找一种方法来初始化这个关联,而不必做这样的事情:

Company company = this.companyRepository.findOneWithSomeCustomQuery(companyId);
Hibernate.initialize(company.getCompanyKeywords());

for (CompanyKeyword ck : company.getCompanyKeywords()) 
    Hibernate.initialize(ck.getKeyword());

上面的代码既不干净,在性能方面也不好。如果可能的话,我想坚持我目前使用 JPQL 查询来获取我的 Company 实体然后初始化某些关联的方法;在我的项目中改变这一点需要相当多的重构。我应该只是“手动”获取与第二个 JPQL 查询的关联,还是有我没有想到的更好的方法?

以下是我的映射。提前致谢!

公司

@Entity
@Table(name = "company")
public class Company implements Serializable 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private int id;


    @Size(max = 20)
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
    private Set<CompanyKeyword> companyKeywords = new HashSet<>();

    // Getters and setters

公司关键字

@Entity
@Table(name = "company_service")
@IdClass(CompanyServicePK.class)
public class CompanyKeyword implements Serializable 
    @Id
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Company.class)
    @JoinColumn(name = "company_id")
    private Company company;

    @Id
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Keyword.class)
    @JoinColumn(name = "keyword_id")
    private Keyword keyword;

    @Column(nullable = true)
    private boolean isActive;


    // Getters and setters

公司关键字PK

public class CompanyServicePK implements Serializable 
    private Company company;
    private Service service;

    public CompanyServicePK()  

    public CompanyServicePK(Company company, Service service) 
        this.company = company;
        this.service = service;
    

    // Getters and setters

    // hashCode()

    // equals()

关键字

@Entity
@Table(name = "keyword")
public class Keyword 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private int id;

    // Fields and getters/setters

【问题讨论】:

【参考方案1】:

您确实需要执行额外的 JPQL 查询,获取公司及其 companyKeyWords 和每个 CompanyKeyWord 的关键字。

您也可以通过简单地循环和初始化每个实体来做到这一点,并且仍然可以通过启用 batch fetching 来避免执行过多的查询。

【讨论】:

以上是关于在 Hibernate 中使用连接表初始化多对多关联的主要内容,如果未能解决你的问题,请参考以下文章

hibernate关联关系(多对多)

hibernate的映射之三(多对多单向关联)

Hibernate的多对多关系

Hibernate学习———— 双向多对多映射关系

hibernate的映射之四(多对多双向关联)

从多对多连接表中检索行的 HQL 查询