对可能为空的属性应用限制

时间:2017-05-23 14:09:46

标签: java hibernate hibernate-criteria

下面是Listener类的类定义,它也是一个数据库实体。它与TLS实体有关系。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "LISTENER")
@IdClass(EntityId.class)

public class Listener implements MultitenantEntity, AuditedEntity {

    @Id
    @Column(name = "LISTENER_ID")
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    public String id;

    @Id
    @Column(name = "LISTENER_INSTANCE_ID")
    private String instanceId;

    @OneToMany(mappedBy="listener", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @Fetch(value= FetchMode.SELECT)
    private List<Path> paths;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns ({
        @JoinColumn(name="TLS_NAME"),
        @JoinColumn(name="INSTANCE_ID")
    })
    @Fetch(value=FetchMode.SELECT)
    private TlsDescriptor tlsDescriptor;

    @Embedded
    @Builder.Default private AuditMetadata audit = new AuditMetadata();
}

以下是TLS的类定义,它也是一个数据库实体:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "TLS_DESCRIPTOR")
@IdClass(EntityId.class)
public class TlsDescriptor implements MultitenantEntity, AuditedEntity        {
    @Id
    @Column(name = "TLS_NAME")
    public String id;

    @Id
    @Column(name = "INSTANCE_ID")
    private String instanceId;

    @Column(name = "TLS_PROTOCOL")
    public String tlsProtocol;

    @Column(name = "CIPHERS")
    public String ciphers;

    @Lob
    @Column(name = "CERTIFICATE", nullable = false)
    public String certificate;

    @Lob
    @Column(name = "PRIVATE_KEY", nullable = false)
    public String privateKey;

    @Embedded
    @Builder.Default private AuditMetadata audit = new AuditMetadata();
}

这里,AuditMetadata是一个包含createdTimestamp和modifiedTimestamp等属性的类,基本上跟踪创建的时间和与之关联的对象的修改时间。

现在,我编写了下面的Hibernate查询,它试图获取以下的侦听器对象:

  1. 在上述时间之后,监听器本身都已更新 'timestamp'已过去

  2. 或之后更新了关联的路径 'timestamp'中提到的时间已过去

  3. 或者相关的tlsDescriptor在'timestamp'过去时提到的时间后更新了

      public List<Listener> findAll(long timestamp, long now, Pageable pageable) {
    return super.find(currentSession()
                    .createCriteria(Listener.class, "listener")
                    .createAlias("listener.paths", "path")
                    .add(Restrictions.or(
                            Restrictions.between("audit.modifyTimestamp", new Date(timestamp), new Date(now)),
                            Restrictions.between("path.audit.modifyTimestamp", new Date(timestamp), new Date(now)),
                            Restrictions.between("listener.tlsDescriptor.audit.modifyTimestamp", new Date(timestamp), new Date(now))))
                    .add(Restrictions.isNotEmpty("listener.paths")),
            pageable);
    

    }

  4. 现在的问题是,path是必填字段,但tlsDescriptor是一个可选字段。所以当tlsDescriptor存在时查询工作正常,但如果它不存在,那么我得到以下错误:

    org.hibernate.QueryException: could not resolve property: tlsDescriptor.audit.modifyTimestamp of:Listener
    

    我尝试使用Hibernate的连接,析取,AND和OR语句来解决此问题,但此错误不断重复!

1 个答案:

答案 0 :(得分:1)

使用带有JoinType.LEFT_OUTER_JOIN的tlsDescriptor别名(如果相关模型为null,则结果不会为空):

public List<Listener> findAll(long timestamp, long now, Pageable pageable) {
return super.find(currentSession()
                .createCriteria(Listener.class, "listener")
                .createAlias("listener.paths", "path")
                .createAlias("listener.tlsDescriptor", "tls", JoinType.LEFT_OUTER_JOIN)
                .add(Restrictions.or(
                        Restrictions.between("audit.modifyTimestamp", new Date(timestamp), new Date(now)),
                        Restrictions.between("path.audit.modifyTimestamp", new Date(timestamp), new Date(now)),
                        Restrictions.between("tls.audit.modifyTimestamp", new Date(timestamp), new Date(now)))),
        pageable);