如何使用Corda VaultQuery API执行含EXISTS子句的子查询?
如何用Corda VaultQuery API实现带EXISTS子句的子查询
问题背景
你已经定义了如下的NodeState线性状态:
data class NodeState( override val linearId: UniqueIdentifier = UniqueIdentifier(), val name: CordaX500Name, val active: Boolean, val services: List<Service> ): LinearState, QueryableState
对应的持久化Schema:
class PersistentNodeState( @Column(name = "linearId") var linearId: String, @Column(name = "name") var name: String, @Column(name = "active") var active: Boolean, @ElementCollection(fetch = FetchType.EAGER) @CollectionTable( name = "node_services", joinColumns = arrayOf( JoinColumn(name = "output_index", referencedColumnName = "output_index"), JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id") ) ) @Column(name = "service") var services: Set<String> )
你希望实现类似以下SQL的Vault查询:
SELECT * FROM NODE_STATE as A where EXISTS (select * from NODE_SERVICES as B where B.TRANSACTION_ID = A.TRANSACTION_ID AND B.SERVICE = 'LEAD_COUNSEL')
解决方案
其实不用手动写EXISTS子句——Corda的VaultQuery API针对@ElementCollection标记的集合属性,会自动帮我们转换为对应的关联查询逻辑。下面是两种实现方式:
方式1:简洁的条件构建
直接针对PersistentNodeState的services属性使用equal条件,底层会自动生成你要的EXISTS子查询:
import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.builder // 构建查询条件:筛选包含'LEAD_COUNSEL'服务的NodeState val queryCriteria = builder { PersistentNodeState::services.equal("LEAD_COUNSEL") } // 执行查询,获取匹配的状态列表 val matchingStates = serviceHub.vaultService.queryBy<NodeState>(queryCriteria).states
方式2:显式关联(复杂场景适用)
如果需要更精细的控制(比如指定关联类型、组合多条件),可以显式创建关联后再构建条件:
import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.builder import javax.persistence.criteria.JoinType val queryCriteria = builder { // 获取PersistentNodeState的JPA实体类引用 val persistentEntity = PersistentNodeState::class.java // 显式关联node_services表(INNER JOIN) val servicesJoin = persistentEntity.join(PersistentNodeState::services.name, JoinType.INNER) // 创建条件:服务等于'LEAD_COUNSEL' val serviceCondition = persistentEntity.get(servicesJoin).equal("LEAD_COUNSEL") // 封装为Vault自定义查询条件 QueryCriteria.VaultCustomQueryCriteria(serviceCondition) } // 执行查询 val matchingStates = serviceHub.vaultService.queryBy<NodeState>(queryCriteria).states
组合额外筛选条件
如果需要同时过滤其他属性(比如只查激活状态的节点),可以直接组合条件:
val queryCriteria = builder { PersistentNodeState::services.equal("LEAD_COUNSEL") .and(PersistentNodeState::active.equal(true)) }
关键说明
- 当你针对
@ElementCollection类型的属性使用equal时,Corda底层的Hibernate会自动生成和你目标SQL逻辑一致的EXISTS子查询,完全不需要手动编写子查询语句。 - 这里
PersistentNodeState的services是Set<String>,所以equal("LEAD_COUNSEL")会匹配所有包含该服务的NodeState实例。
内容的提问来源于stack exchange,提问作者N.S.
相关产品推荐
相关产品推荐

