M:N 关联未通过 Hibernate 查询获取

问题描述 投票:0回答:1

我通过

Thread
实体在
Participant
ThreadParticipant
之间建立多对多关系(因为关联有一个附加字段)。我有以下映射。

线程实体

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

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "thread", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    private Collection<ThreadParticipant> threadParticipants = new HashSet<>();

    // Getters and setters
}

参与者实体

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

    @ManyToOne(fetch = FetchType.LAZY, optional = true, targetEntity = Account.class, cascade = { CascadeType.PERSIST })
    @JoinColumn(name = "account_id")
    private Account account;

    @ManyToOne(fetch = FetchType.LAZY, optional = true, targetEntity = Company.class)
    @JoinColumn(name = "company_id")
    private Company company;

    // Getters and setters
}

线程参与者实体

@Entity
@Table(name = "thread_participant")
@IdClass(ThreadParticipantPK.class)
public class ThreadParticipant implements Serializable {
    @Id
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Participant.class, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "participant_id")
    private Participant participant;

    @Id
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Thread.class)
    @JoinColumn(name = "thread_id")
    private Thread thread;

    @Column(name = "last_viewed", nullable = true)
    private Date lastViewed;


    // Getters and setters
}

线程参与者PK

public class ThreadParticipantPK implements Serializable {
    private Thread thread;
    private Participant participant;

    public ThreadParticipantPK() { }

    public ThreadParticipantPK(Thread thread, Participant participant) {
        this.thread = thread;
        this.participant = participant;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof ThreadParticipantPK)) return false;

        ThreadParticipantPK that = (ThreadParticipantPK) o;

        if (!participant.equals(that.participant)) return false;
        if (!thread.equals(that.thread)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = thread.hashCode();
        result = 31 * result + participant.hashCode();
        return result;
    }

    // Getters and setters
}

现在,我尝试使用以下查询(使用 Spring Data JPA)和 Hibernate 作为我的 JPA 提供程序来获取线程。

@Repository
public interface ThreadRepository extends JpaRepository<Thread, Integer> {
    @Query("select distinct t from Thread t inner join fetch t.threadParticipants tp inner join fetch tp.participant p left join fetch p.account a left join fetch p.company c")
    public List<Thread> test();
}

问题在于,当

ThreadParticipants
内关联的获取类型设置为
FetchType.LAZY
时,
Thread.threadParticipants
集合为空。因此,如果我将关联设置为
FetchType.EAGER
,则
Thread.threadParticipants
包含两个元素(理应如此)。然而,在这种情况下,Hibernate 会发疯并执行四个 SQL 查询来获取单个线程。

Hibernate: select thread0_.id as id1_18_0_, threadpart1_.participant_id as particip2_19_1_, threadpart1_.thread_id as thread_i3_19_1_, participan2_.id as id1_12_2_, account3_.id as id1_0_3_, company4_.id as id1_6_4_, thread0_.created as created2_18_0_, thread0_.last_activity as last_act3_18_0_, thread0_.subject as subject4_18_0_, threadpart1_.last_viewed as last_vie1_19_1_, threadpart1_.thread_id as thread_i3_18_0__, threadpart1_.participant_id as particip2_19_0__, threadpart1_.thread_id as thread_i3_19_0__, participan2_.account_id as account_2_12_2_, participan2_.company_id as company_3_12_2_, account3_.email as email2_0_3_, account3_.facebook_profile_id as facebook3_0_3_, account3_.first_name as first_na4_0_3_, account3_.last_name as last_nam5_0_3_, account3_.middle_name as middle_n6_0_3_, company4_.additional_address_text as addition2_6_4_, company4_.banner_name as banner_n3_6_4_, company4_.ci_number as ci_numbe4_6_4_, company4_.city_id as city_id22_6_4_, company4_.co_name as co_name5_6_4_, company4_.company_type_code as company_6_6_4_, company4_.created as created7_6_4_, company4_.description as descript8_6_4_, company4_.email as email9_6_4_, company4_.last_modified as last_mo10_6_4_, company4_.logo_name as logo_na11_6_4_, company4_.name as name12_6_4_, company4_.number_of_reviews as number_13_6_4_, company4_.phone_number as phone_n14_6_4_, company4_.postal_box as postal_15_6_4_, company4_.rating as rating16_6_4_, company4_.second_phone_number as second_17_6_4_, company4_.street_name as street_18_6_4_, company4_.street_number as street_19_6_4_, company4_.teaser as teaser20_6_4_, company4_.website as website21_6_4_ from thread thread0_ inner join thread_participant threadpart1_ on thread0_.id=threadpart1_.thread_id inner join participant participan2_ on threadpart1_.participant_id=participan2_.id left outer join account account3_ on participan2_.account_id=account3_.id left outer join company company4_ on participan2_.company_id=company4_.id
Hibernate: select participan0_.id as id1_12_0_, participan0_.account_id as account_2_12_0_, participan0_.company_id as company_3_12_0_ from participant participan0_ where participan0_.id=?
Hibernate: select thread0_.id as id1_18_0_, thread0_.created as created2_18_0_, thread0_.last_activity as last_act3_18_0_, thread0_.subject as subject4_18_0_ from thread thread0_ where thread0_.id=?
Hibernate: select participan0_.id as id1_12_0_, participan0_.account_id as account_2_12_0_, participan0_.company_id as company_3_12_0_ from participant participan0_ where participan0_.id=?

显然它正在为每个参与者执行一个查询,并为每个线程执行两个查询。所以,如果没有

FetchType.EAGER
,我的代码根本无法工作,但是有了它,我的数据库就会被杀死。我尝试在
@OneToMany
Participant
之间添加
ThreadParticipant
关联(类似于从
Thread
ThreadParticipant
的关联),但结果相同。我还尝试将所有别名添加到查询的字段列表中,但无济于事。

为什么会发生这种情况?我的映射或查询错误吗?预先感谢您!

java hibernate jpa orm spring-data-jpa
1个回答
0
投票

尝试将一对多集合更改为

Set

@OneToMany(
    mappedBy = "thread", 
    cascade = {CascadeType.PERSIST, CascadeType.MERGE}
)
private Set<ThreadParticipant> threadParticipants = new HashSet<>();

如果您只有

LAZY
关联,则永远不应该生成附加查询。这可能是因为
many-to-one
one-to-one
关系默认为
EAGER
。尝试将它们设置为
LAZY

© www.soinside.com 2019 - 2024. All rights reserved.