【问题标题】:hibernate multiple @OneToMany relationships generating more results in parent relationship休眠多个@OneToMany 关系在父关系中产生更多结果
【发布时间】:2020-01-01 06:58:16
【问题描述】:

我将从结果开始。在下一张图片中,我将显示 company.userAccount 的结果内容。在数据库中,我只有两家公司分配给同一个用户,其中一家公司有 7 项服务。

@Entity
@Table(name = "user_account")
@Data
@Introspected
@JsonIgnoreProperties(value = {"id"})
public class UserAccount {
    ...

    @OneToMany(mappedBy = "userAccount", fetch = FetchType.EAGER)
    private List<Company> companies = new ArrayList<>();

}


@Entity
@Table(name = "company")
@Data
@Introspected
@ToString(exclude = {"userAccount"})
@JsonIgnoreProperties(value = {"id", "userAccount"})
public class Company {
    ...

    @ManyToOne(optional = false)
    @JoinColumn(name = "user_account_id", updatable = false, nullable = false)
    private UserAccount userAccount;

}


@Entity
@Table(name = "service")
@Data
@Introspected
@ToString(exclude = {"company"})
@JsonIgnoreProperties(value= {"id", "company"})
public class Service {
    ...

    @ManyToOne(optional = false)
    @JoinColumn(name = "company_id", updatable = false, nullable = false)
    private Company company;

}


@Transactional
public Service saveService(@Valid @Uuid UUID companyUuid, SaveServiceCommand command) {
    Company company = companyRepository.getCompanyByUuid(companyUuid).orElseThrow(() -> new NoSuchElementException("unrecognized company"));

    Service service = new Service();
    service.setCompany(company);
    service.setName(command.getName());
    service.setUuid(UUID.randomUUID().toString());

    return companyRepository.saveCompanyService(service);
}

@Transactional
public Service saveCompanyService(@Valid Service service) {
    entityManager.persist(service);
    return service;
}

生成的查询(简化)是

select * from user_account a left outer join company c on a.id=c.user_account_id left outer join service s on c.id=s.company_id; 

这会生成

预期结果:我希望在 UserAccount 中只看到 2 家公司,而在其中一家公司中看到 6 项服务。为什么我有这个结果?为什么同一个公司对象在列表中多次出现?我怎样才能避免这种情况?

我相信一种解决方案是将@OneToMany 关系的获取类型更改为 LAZY(因为它们是默认的)(已经测试过这个解决方案并且它有效)但是如果我需要这种类型的场景怎么办?

【问题讨论】:

    标签: java sql hibernate jpa hibernate-mapping


    【解决方案1】:

    是的,正如您所说,有 2 家公司。您会注意到,所有对象都是相同的(哈希匹配)。这背后的原因是查询为一家公司生成了 6 行,而 hibernate 使用的 PersistenceBag 默认情况下不会删除重复项。将distinct 传递给你的sql 是行不通的,因为只有一个父实体。

    但这可以通过使用hibernate的查询提示来实现。将 QueryHints.HINT_PASS_DISTINCT_THROUGH 传递给您的 Query 只会删除重复的孩子。

    更多信息可以参考this来源。

    【讨论】:

    • 这如何应用于关系定义生成的查询?
    • @tzortzik 如前所述,这是一个休眠标准,您必须使用其他机制,例如EntityManager#createQuery,您可以在其中使用setHint 传递提示。其他方法是手动删除重复项,但这是需要维护的额外逻辑。
    猜你喜欢
    • 1970-01-01
    • 2019-11-29
    • 2015-12-22
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多