Hibernate简单的一对多查询无限查询

时间:2017-07-10 14:40:01

标签: hibernate jpa criteria-api

我有以下表结构:用户对话消息。用户具有对话框列表和消息列表。 Dialog包含用户列表和消息列表。而Message则引用了对话框和用户。所以

用户 - 对话框:many to many

消息 - 用户:many to one

消息 - 对话many to one

实体:

对话框

@Entity
@Table(name = "dialogs")
public class Dialog {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_dialog")
    private Long id;

    @Column(name = "dialog_name")
    private String dialogName;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "dialogs_users",
            joinColumns = @JoinColumn(name = "id_dialog"),
            inverseJoinColumns = @JoinColumn(name = "id_user"))
    private List<User> dialogUsers;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "dialog")
    private List<Message> messages = new ArrayList<>();

    //default constructor and getters setters and hashCode equals toString
}

用户

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_user")
    private Long id;

    @NotNull
    @Column(name = "full_name")
    private String fullName;

    @NotNull
    @Column(name = "email")
    private String email;

    @NotNull
    @Column(name = "active")
    private boolean active;

    @NotNull
    @Column(name = "password")
    private String password;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
    private List<Message> messages;

    @ElementCollection(targetClass = Role.class)
    @CollectionTable(name = "user_roles",
            joinColumns = @JoinColumn(name = "user"))
    @Column(name = "role")
    @Enumerated(EnumType.ORDINAL)
    private List<Role> roles = new ArrayList<>();

    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "dialogUsers")
    private List<Dialog> dialogs = new ArrayList<>();

    //default constructor and getters setters and hashCode equals toString
}

消息

@Entity
@Table(name = "messages")
public class Message {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_message")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id_dialog")
    private Dialog dialog;

    @Column(name = "value")
    private String value;

    @Column(name = "date_time")
    private LocalDateTime dateTime;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id_user")
    private User user;

    //default constructor and getters setters and hashCode equals toString
}

我的entityManager查询

@Override
public List<Message> findMessagesByDialog(Long dialogId) {
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Message> criteria = builder.createQuery(Message.class);
    Root<Dialog> dialog = criteria.from(Dialog.class);

    Join<Dialog, Message> messages = dialog.join(Dialog_.messages);

    criteria.select(messages).where(builder.equal(dialog.get(Dialog_.id), dialogId));
    return entityManager.createQuery(criteria).getResultList();
}

执行此查询时我得到的堆栈跟踪

Hibernate: 
    select
        messages1_.id_message as id_messa1_2_,
        messages1_.date_time as date_tim2_2_,
        messages1_.id_dialog as id_dialo4_2_,
        messages1_.id_user as id_user5_2_,
        messages1_.value as value3_2_ 
    from
        dialogs dialog0_ 
    inner join
        messages messages1_ 
            on dialog0_.id_dialog=messages1_.id_dialog 
    where
        dialog0_.id_dialog=1
Hibernate: 
    select
        dialog0_.id_dialog as id_dialo1_0_0_,
        dialog0_.dialog_name as dialog_n2_0_0_ 
    from
        dialogs dialog0_ 
    where
        dialog0_.id_dialog=?
Hibernate: 
    select
        user0_.id_user as id_user1_4_0_,
        user0_.active as active2_4_0_,
        user0_.email as email3_4_0_,
        user0_.full_name as full_nam4_4_0_,
        user0_.password as password5_4_0_ 
    from
        users user0_ 
    where
        user0_.id_user=?
Hibernate: 
    select
        user0_.id_user as id_user1_4_0_,
        user0_.active as active2_4_0_,
        user0_.email as email3_4_0_,
        user0_.full_name as full_nam4_4_0_,
        user0_.password as password5_4_0_ 
    from
        users user0_ 
    where
        user0_.id_user=?
Hibernate: 
    select
        dialoguser0_.id_dialog as id_dialo1_1_0_,
        dialoguser0_.id_user as id_user2_1_0_,
        user1_.id_user as id_user1_4_1_,
        user1_.active as active2_4_1_,
        user1_.email as email3_4_1_,
        user1_.full_name as full_nam4_4_1_,
        user1_.password as password5_4_1_ 
    from
        dialogs_users dialoguser0_ 
    inner join
        users user1_ 
            on dialoguser0_.id_user=user1_.id_user 
    where
        dialoguser0_.id_dialog=?

..等等

我知道我有多个引用,一个实体引用另一个,但所有提取都是懒惰的。而且你也可以认为问题出在方法 hashCode,equals或toString 中,它们没有引用另一个实例(只有自己的字段)。

  

我不排除我在我的实体声明中的某个地方弄错了

1 个答案:

答案 0 :(得分:0)

您可以在dialogUsers实体中使用杰克逊的@JsonIgnore annotationDialog列表,这样可以防止Hibernate在选择Dialog时为用户提取列表:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "dialogs_users",
        joinColumns = @JoinColumn(name = "id_dialog"),
        inverseJoinColumns = @JoinColumn(name = "id_user"))
@JsonIgnore
private List<User> dialogUsers;