简体   繁体   中英

Applying Restrictions on an attribute that may or may not be null

Below is the class definition for Listener class which is also a database entity. It has a relationship with TLS entity.

@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();
}

Below is the class definition for TLS, which is also a database entity:

@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();
}

Here, AuditMetadata is a class which contains attributes such as createdTimestamp and modifiedTimestamp, essentially keeping track of the created time and modified time of the object it is associated with.

Now, I wrote the below Hibernate query which tries to fetch the listener objects for which:

  1. Either the listener itself was updated after the time mentioned in the 'timestamp' elapsed

  2. Or the associated path was updated after the time mentioned in the 'timestamp' elapsed

  3. Or the associated tlsDescriptor was updated after the time mentioned in the 'timestamp' elapsed

      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); 

    }

Now the problem is, path is a mandatory field but tlsDescriptor is an optional field. So the query works fine when tlsDescriptor is present, but if it is absent, then I get the following error:

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

I tried trying to resolve this using conjunction, disjunction, AND and OR statements of Hibernate, but this error keeps repeating!

Use alias for tlsDescriptor with JoinType.LEFT_OUTER_JOIN (so result will not be empty if related model is 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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM