JPQL HQL 查询在 class 层次结构之上运行,具有联合继承策略并应用 DTO 投影

JPQL HQL query operating on top of class hierarchy with joined inheritance strategy and applying DTO projection

假设我有以下 class 继承策略的层次结构:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Notification {

    protected Long id;
    protected Long code;

    protected Notification() {
    }
}

@Entity
@PrimaryKeyJoinColumn(name = "NOTIFICATION_ID")
public class Sms extends Notification {

    private String phoneNumber;
    private String smsText;

    public Sms() {
    }
}

@Entity
@PrimaryKeyJoinColumn(name = "NOTIFICATION_ID")
public class Push extends Notification {

    private String application;
    private String pushText;
    
    public Push() {
    }
}

我如何编写 JPQL / HQL 查询将 return List<NotificationDetails> 其中 NotificationDetails 是:

public class NotificationDetails {

    private final String contact;
    private final String content;

    public NotificationDetails(String contact, String content) {
        this.contact = contact;
        this.content = content;
    }
}

其中映射应如下所示:

contact - phoneNumber / application
content - smsText / pushText

你可以尝试使用下面的jpql:

List<NotificationDetails> results = em.createQuery(
   "select new com.your.entities.NotificationDetails( "
 + "  coalesce(s.phoneNumber, p.application), "
 + "  coalesce(s.smsText, p.pushText) "
 + ") from Notification n "
 + "left join Sms s on s.id = n.id "
 + "left join Push p on p.id = n.id ",
 NotificationDetails.class).getResultList();

有效,但生成效率很低sql:

select
  coalesce(sms1_.sms_phone, push2_.push_app) as col_0_0_,
  coalesce(sms1_.sms_text, push2_.push_text) as col_1_0_ 
from TEST_SCHEMA.TST_NOTIFICATION notificati0_ 
left outer join (
   TEST_SCHEMA.TST_SMS sms1_ 
   inner join TEST_SCHEMA.TST_NOTIFICATION sms1_1_
      on sms1_.sms_not_id=sms1_1_.not_id
) on (sms1_.sms_not_id=notificati0_.not_id) 
left outer join (
   TEST_SCHEMA.TST_PUSH push2_ 
   inner join TEST_SCHEMA.TST_NOTIFICATION push2_1_ 
      on push2_.push_not_id=push2_1_.not_id
) on (push2_.push_not_id=notificati0_.not_id)

如果性能在这里很重要,我想最好使用本机查询并将其映射(对于 example 通过 @SqlResultSetMapping)到 NotificationDetails dto。

Hibernate 支持隐式子类型 属性 解析,因此您可以使用如下查询:

List<NotificationDetails> results = em.createQuery(
   "select new com.your.entities.NotificationDetails(coalesce(n.phoneNumber, n.application),  coalesce(n.smsText, n.pushText)) from Notification n ",
   NotificationDetails.class
).getResultList();