R3 Corda: 升级 CorDapp(非平台版本升级)- S
原文地址:https://docs.corda.net/upgrading-cordapps.html#state-schemas
默认的,所有的 state 对象都会以被序列化为字节格式的字符串而存到数据库中,并且会被他们的 StateRef
引用。然而对某些特定的属性或者一些属性的集合的序列化也是可以定义自定义的 schemas 的,所以他们就可以从一个数据源被检索而不是直接检索 Corda Vault。这个是通过实现 QueryableState
接口并且对这个 state 创建一个自定义的 ORM(Object Relational Mapper) 来实现的。
针对于向后兼容性,像添加新的 columns 这样的改动,升级一个 state schema 的过程其实是对已经存在的 ORM 进行扩展。比如,我们可以将下边的 schema:
object ObligationSchemaV1 : MappedSchema(Obligation::class.java, 1, listOf(ObligationEntity::class.java)) {
@Entity @Table(name = "obligations")
class ObligationEntity(obligation: Obligation) : PersistentState() {
@Column var currency: String = obligation.amount.token.toString()
@Column var amount: Long = obligation.amount.quantity
@Column @Lob var lender: ByteArray = obligation.lender.owningKey.encoded
@Column @Lob var borrower: ByteArray = obligation.borrower.owningKey.encoded
@Column var linear_id: String = obligation.linearId.id.toString()
}
}
更新成:
object ObligationSchemaV1 : MappedSchema(Obligation::class.java, 1, listOf(ObligationEntity::class.java)) {
@Entity @Table(name = "obligations")
class ObligationEntity(obligation: Obligation) : PersistentState() {
@Column var currency: String = obligation.amount.token.toString()
@Column var amount: Long = obligation.amount.quantity
@Column @Lob var lender: ByteArray = obligation.lender.owningKey.encoded
@Column @Lob var borrower: ByteArray = obligation.borrower.owningKey.encoded
@Column var linear_id: String = obligation.linearId.id.toString()
@Column var defaulted: Bool = obligation.amount.inDefault // NEW COLUMN!
}
}
因此当添加一个新的 column 的时候,给它一个默认值。
对于一个非向后兼容的改动,那么必须要使用 ContractUpgradeFlow
或者 AbstractStateReplacementFlow
,因为必须要对 state 也要做改动。对于一个非向后兼容的改动,比如删除了一个 column(比如因为某个属性需要从 state 对象中被删除),更新的过程应该是定义另外一个 ORM,然后将它添加到你的 QueryableState
的 supportedSchemas
属性中,像下边这样:
override fun supportedSchemas(): Iterable<MappedSchema> = listOf(ExampleSchemaV1, ExampleSchemaV2)
然后在 generateMappedObject
中添加对新的 schema 的支持:
override fun generateMappedObject(schema: MappedSchema): PersistentState {
return when (schema) {
is DummyLinearStateSchemaV1 -> // Omitted.
is DummyLinearStateSchemaV2 -> // Omitted.
else -> throw IllegalArgumentException("Unrecognised schema $schema")
}
}
通过这种方式,当 state 对象被存储到 vault 中的时候,它的代表(representation)会被分别存储到两个数据库表中,每个代表着一个支持的 schema。