使用 join table 在 Hibernate 中初始化多对多关联
Initializing many-to-many association in Hibernate with join table
我有一个 Company
实体,我通过 Hibernate 的 JPQL 查询获取该实体。该实体与 Keyword
实体具有多对多关联。由于连接 table 有一个附加列 is_active
,因此此 table 已映射到 CompanyKeyword
实体。所以联想是这样的:
Company <-- CompanyKeyword --> Keyword
现在,来自 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;
}
}
对于 "normal" 多对多关联,这会很有效,因为所有关联的实体都将在单个查询中获取。但是,由于我在 Company
和 Keyword
之间有一个实体,Hibernate 只会初始化 关联的第一部分 ,即从 Company
到 CompanyKeyword
,而不是从 CompanyKeyword
到 Keyword
。我希望这是有道理的。我正在寻找一种方法来初始化这个关联,而不必做这样的事情:
Company company = this.companyRepository.findOneWithSomeCustomQuery(companyId);
Hibernate.initialize(company.getCompanyKeywords());
for (CompanyKeyword ck : company.getCompanyKeywords()) {
Hibernate.initialize(ck.getKeyword());
}
以上代码既不干净,性能也不佳。如果可能的话,我想坚持我目前的方法,即使用 JPQL 查询来获取我的 Company
实体,然后再初始化某些关联;在我的项目中改变这一点需要相当多的重构。我应该 "manually" 获取与第二个 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
}
您确实需要执行一个额外的 JPQL 查询,获取公司及其 companyKeyWords 以及每个 CompanyKeyWord 的关键字。
您也可以通过简单地循环和初始化每个实体来实现,并且仍然可以通过启用 batch fetching.
来避免执行太多查询
我有一个 Company
实体,我通过 Hibernate 的 JPQL 查询获取该实体。该实体与 Keyword
实体具有多对多关联。由于连接 table 有一个附加列 is_active
,因此此 table 已映射到 CompanyKeyword
实体。所以联想是这样的:
Company <-- CompanyKeyword --> Keyword
现在,来自 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;
}
}
对于 "normal" 多对多关联,这会很有效,因为所有关联的实体都将在单个查询中获取。但是,由于我在 Company
和 Keyword
之间有一个实体,Hibernate 只会初始化 关联的第一部分 ,即从 Company
到 CompanyKeyword
,而不是从 CompanyKeyword
到 Keyword
。我希望这是有道理的。我正在寻找一种方法来初始化这个关联,而不必做这样的事情:
Company company = this.companyRepository.findOneWithSomeCustomQuery(companyId);
Hibernate.initialize(company.getCompanyKeywords());
for (CompanyKeyword ck : company.getCompanyKeywords()) {
Hibernate.initialize(ck.getKeyword());
}
以上代码既不干净,性能也不佳。如果可能的话,我想坚持我目前的方法,即使用 JPQL 查询来获取我的 Company
实体,然后再初始化某些关联;在我的项目中改变这一点需要相当多的重构。我应该 "manually" 获取与第二个 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
}
您确实需要执行一个额外的 JPQL 查询,获取公司及其 companyKeyWords 以及每个 CompanyKeyWord 的关键字。
您也可以通过简单地循环和初始化每个实体来实现,并且仍然可以通过启用 batch fetching.
来避免执行太多查询