首页 > 解决方案 > 具有一对多的 Hibernate (JPA) 继承

问题描述

我正在构建一个规则引擎系统,我希望允许用户获取他们请求的规则和他们作为通知收件人订阅的规则

我正在努力编写一个查询,通过给定用户名获取用户名请求的所有规则,或者他在通知中列出

由于我是 Hibernate + Spring JPA 的新手,我很难确定这是设计不佳还是缺乏构建复杂查询的知识

我的方案描述如下。

规则.java

@Entity
@Table(name = "rule")
public class Rule implements Serializable {
    ...
    @Column(name = "requester")
    private String requester;

    @OneToMany
    @JoinColumn(name = "rule_id", referencedColumnName = "id")
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    private Set<Action> actions = new HashSet<>();
    ...
// getter, setters
}

动作.java

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "action_type")
public class Action implements Serializable {
...
    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "active")
    private Boolean active;
...
// getter, setters
}

任务

@Entity
public class Task extends Action {
...
    @Column(name = "task_name")
    private String taskName;
...
// getter, setters
}

警报

@Entity
public class Alert extends Action implements Serializable {
...
    @ManyToMany
    @JoinTable(
        name = "alert_notification",
        joinColumns = @JoinColumn(name = "alert_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "notification_id", referencedColumnName = "id"))
    private Set<Notification> notifications = new HashSet<>();
...
// getter, setters
}

通知

@Entity
@Table(name = "notification")
@Inheritance(strategy = InheritanceType.JOINED)
public class Notification implements Serializable {
...
    @Column(name = "username")
    private String username;
// getter, setters
...
}

电子邮件通知

@Entity
@Table(name = "email_notification")
public class EmailNotification extends Notification {
...
    @Column(
        name = "email",
        nullable = false
    )
    private String email;
...
// getter, setters
}

松弛通知

@Entity
@Table(name = "teams_notification")
public class SlackNotification extends Notification {
...
// getter, setters
...
}

我尝试运行下面的 JPA 查询,但没有成功。

@Transactional(readOnly = true)
    public List<Rule> findAllByLogin(String login) {
        TypedQuery<Rule> query = em.createQuery("select r from Rule r join fetch r.actions a join fetch a.notifications n " +
            "where type(a) = Alert and n.login = '" + login +"' or r.requester = '" + login +"'", Rule.class);
        return query.getResultList();
    }

任何帮助表示赞赏。

标签: javaspringhibernatejpasingle-table-inheritance

解决方案


你的设计看起来不错。我假设查询错误是因为动作和通知之间没有关系,所以加入

join fetch a.notifications

应该与警报实体一起制作。根据这个答案,您应该使用 TREAT 指令:

    TypedQuery<Rule> query = em.createQuery("select r from Rule r "
        + "join fetch TREAT (r.actions as Alert) a "
        + "join fetch a.notifications n  " 
        + "where type(a) = Alert and n.login = '" + login +"' or r.requester = '" + login +"'", Rule.class);

推荐阅读