You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:56:52