Hibernate JPA标准:从实体层次结构进行投影时,使用左外部联接而不是内部联接

Hibernate JPA标准:从实体层次结构进行投影时,使用左外部联接而不是内部联接,hibernate,jpa,spring-data-jpa,jpa-2.0,criteria-api,Hibernate,Jpa,Spring Data Jpa,Jpa 2.0,Criteria Api,假设我有1个父实体和2个子实体: @Entity @Inheritance(strategy = InheritanceType.JOINED) public abstract class Notification { protected Long id; protected Long code; protected Notification() { } } @Entity @PrimaryKeyJoinColumn(name = "NOTIFIC

假设我有1个父实体和2个子实体:

@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() {
    }
}
我想使用JPA标准API进行如下投影:

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<NotificationSummary> query = builder.createQuery(NotificationSummary.class);
Root<Notification> root = query.from(Notification.class);

query.select(builder.construct(NotificationSummary.class,
        root.get("code"),
        builder.treat(root, Sms.class).get("smsText"),
        builder.treat(root, Push.class).get("pushText"),
        builder.treat(root, Sms.class).get("phoneNumber"),
        builder.treat(root, Push.class).get("application")
));

class NotificationSummary {

    private final Long code;
    private final String smsText;
    private final String pushText;
    private final String phoneNumber;
    private final String application;

    public NotificationSummary(Long code, String smsText, String pushText, String phoneNumber, String application) {
        this.code = code;
        this.smsText = smsText;
        this.pushText = pushText;
        this.phoneNumber = phoneNumber;
        this.application = application;     
    }
}   
我想它会留在外面


我是否可以将其更改为左外部联接而不是内部联接?

这是不可能的,因为HQL中的
TREAT
目前导致内部联接,因为JPA规范在语义上不是很清楚。在我看来,这可能会有不同的解释,但这就是现在的情况

在HQL中,您实际上可以省略
TREAT
来隐式访问子类型属性,这将导致左连接,就像您所期望的那样。如果您不想在HQL中重写您的查询,那么您可以使用一个不同的JPA标准实现,它本质上呈现给JPQL/HQL。Blaze Persistence是一个在JPA/Hibernate之上工作的库,它支持许多高级SQL特性,同时保持在JPA模型的范围内。以下是使用JPA标准实施的快速入门链接:

您还需要一些,但由于您想要创建投影,您可能也喜欢它,它允许您以更具声明性的方式创建投影。对于实体视图,您的用例可能如下所示:

@EntityView(Notification.class)
public interface NotificationSummary {
    Long getCode();
    @Mapping("TREAT(this AS Sms).smsText")
    String getSmsText();
    @Mapping("TREAT(this AS Push).pushText")
    String getPushText();
    @Mapping("TREAT(this AS Sms).phoneNumber")
    String getPhoneNumber();
    @Mapping("TREAT(this AS Push).application")
    String getApplication();
}  

非常感谢,关于HQL无需治疗即可工作的经验教训。HQL查询现在适用于我。稍后我将尝试blaze持久性项目。
@EntityView(Notification.class)
public interface NotificationSummary {
    Long getCode();
    @Mapping("TREAT(this AS Sms).smsText")
    String getSmsText();
    @Mapping("TREAT(this AS Push).pushText")
    String getPushText();
    @Mapping("TREAT(this AS Sms).phoneNumber")
    String getPhoneNumber();
    @Mapping("TREAT(this AS Push).application")
    String getApplication();
}