对可能为 null 或可能不为 null 的属性应用限制
Applying Restrictions on an attribute that may or may not be null
下面是 Listener class 的 class 定义,它也是一个数据库实体。它与 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 的 class 定义,它也是一个数据库实体:
@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 是一个class,它包含createdTimestamp 和modifiedTimestamp 等属性,本质上是跟踪与其关联的对象的创建时间和修改时间。
现在,我写了下面的 Hibernate 查询,它试图获取侦听器对象:
监听器本身是在中提到的时间之后更新的
'timestamp' 过去了
或者关联路径更新后
'timestamp' 中提到的时间已经过去
或者关联的 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);
}
现在的问题是,path 是必填字段,但 tlsDescriptor 是可选字段。因此,当存在 tlsDescriptor 时查询工作正常,但如果不存在,则会出现以下错误:
org.hibernate.QueryException: could not resolve property: tlsDescriptor.audit.modifyTimestamp of:Listener
我尝试使用 Hibernate 的合取、析取、AND 和 OR 语句来解决此问题,但此错误不断重复!
使用 JoinType.LEFT_OUTER_JOIN 的 tlsDescriptor 别名(如果相关模型为空,结果将不会为空):
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);
下面是 Listener class 的 class 定义,它也是一个数据库实体。它与 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 的 class 定义,它也是一个数据库实体:
@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 是一个class,它包含createdTimestamp 和modifiedTimestamp 等属性,本质上是跟踪与其关联的对象的创建时间和修改时间。
现在,我写了下面的 Hibernate 查询,它试图获取侦听器对象:
监听器本身是在中提到的时间之后更新的 'timestamp' 过去了
或者关联路径更新后 'timestamp' 中提到的时间已经过去
或者关联的 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);
}
现在的问题是,path 是必填字段,但 tlsDescriptor 是可选字段。因此,当存在 tlsDescriptor 时查询工作正常,但如果不存在,则会出现以下错误:
org.hibernate.QueryException: could not resolve property: tlsDescriptor.audit.modifyTimestamp of:Listener
我尝试使用 Hibernate 的合取、析取、AND 和 OR 语句来解决此问题,但此错误不断重复!
使用 JoinType.LEFT_OUTER_JOIN 的 tlsDescriptor 别名(如果相关模型为空,结果将不会为空):
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);