问题描述
我正在构建一个规则引擎系统,我希望允许用户获取他们请求的规则以及他们作为通知接收者订阅的规则
我正在努力编写一个查询,通过给定用户名获取用户名请求的所有规则,或者他列在通知中
由于我是 Hibernate + Spring JPA 的新手,我很难确定这是设计不佳的情况还是只是缺乏构建复杂查询的知识
我的方案描述如下。
Rule.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
}
Action.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
}
SlackNotification
@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();
}
感谢任何帮助。
解决方法
你的设计看起来不错。 我假设查询错误是因为动作和通知之间没有关系,所以加入
join fetch a.notifications
应该与警报实体一起制作。 基于此 answer,您应该使用 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);
,
通过将类 Action.java
上的继承类型修改为 SINGLE_TABLE
并使用以下查询,我能够解决该问题
"select r from Rule r left join fetch r.actions action " +
"left join action.notifications n where r.requester = :name or (type(action) = Alert and n.login = :login)"