当前位置: 首页 > 面试题库 >

Corda:如何实现状态数据之间持久化的层次关系

祝叶五
2023-03-14
问题内容

摘要

我修改了基本的令牌发行Corda
Bootcamp应用程序来演示此问题。我想在TokenStates与TokenChildren之间建立一对多关系的双向映射。

持久保存分层数据的最佳实践是什么? 是否可以在状态模式中使用JPA注释来实现此目的?

我有一个状态-
TokenState,其中包含一些任意数据以及Collection带有类的对象TokenChild。该列表的目的是促进H2中的记录之间的一对多关系。该州的关联架构具有相应的JPA批注(@OneToMany和@ManyToOne-
请参见下面的代码段)。本TokenState类引用适当的模式-
TokenSchemaV1supportedSchemasgenerateMappedObject方法。

当我TokenIssueFlow在部署和运行节点之后从html" target="_blank">控制台运行(也包含在代码段中)时,事务成功完成,但没有任何token_child_states表持久化到h2。

其他注意事项

  • 我还尝试实现一种不同的策略,其中Token
    和TokenChildren都是唯一状态(而不是一个整体
    状态)。有关更多详细信息,请参见此Github问题。

  • 另一个解决方案可能是将Tokens和TokenChildren作为单独的状态,并在h2中手动保留外键以促进这种关系,但这似乎是一种解决方法,而不是解决方案。

  • 类之间更深层嵌套的关系有哪些后果?(例如-具有TokenGrandChildren的TokenChildren的人为示例)。如何使用generateMappedObject()supportedSchemas()创建所需的数据模型?

令牌状态

public class TokenState implements LinearState, QueryableState {



    private final Party owner;

    private final Party issuer;

    private final int amount;

    private final UniqueIdentifier linearId;

    private List<TokenSchemaV1.PersistentChildToken> listOfPersistentChildTokens;



    public TokenState (Party issuer, Party owner, int amount, UniqueIdentifier linearId, List<TokenSchemaV1.PersistentChildToken> listOfPersistentChildTokens) {

        this.owner = owner;

        this.issuer = issuer;

        this.amount = amount;

        this.linearId = linearId;

        this.listOfPersistentChildTokens = listOfPersistentChildTokens;

    }



    public Party getOwner() {

        return owner;

    }



    public Party getIssuer() {

        return issuer;

    }



    public int getAmount() {

        return amount;

    }



    @Override

    public UniqueIdentifier getLinearId() {

        return linearId;

    }



    public List<TokenSchemaV1.PersistentChildToken> getListOfPersistentChildTokens() {

        return listOfPersistentChildTokens;

    }



    @Override

    public PersistentState generateMappedObject(MappedSchema schema) {

        if (schema instanceof TokenSchemaV1) {

            return new TokenSchemaV1.PersistentToken(

                    this.getOwner().getName().toString(),

                    this.getIssuer().getName().toString(),

                    this.getAmount(),

                    this.linearId.getId(),

                    this.getListOfPersistentChildTokens()

            );

        } else {

            throw new IllegalArgumentException("Unrecognised schema $schema");

        }

    }



    @Override

    public Iterable<MappedSchema> supportedSchemas() {

        return ImmutableList.of(new TokenSchemaV1());

    }



    @NotNull

    @Override

    public List<AbstractParty> getParticipants() {

        return ImmutableList.of(issuer, owner);

    }



}

令牌模式V1

@CordaSerializable

public class TokenSchemaV1 extends MappedSchema {



    public TokenSchemaV1() {

        super(TokenSchema.class, 1, ImmutableList.of(PersistentToken.class, PersistentChildToken.class));

    }



    @Entity

    @Table(name = "token_states")

    public static class PersistentToken extends PersistentState {

        @Column(name = "owner") private final String owner;

        @Column(name = "issuer") private final String issuer;

        @Column(name = "amount") private final int amount;

        @Column(name = "linear_id") private final UUID linearId;

        @OneToMany(mappedBy = "persistentToken") private final List<PersistentChildToken> listOfPersistentChildTokens;

        //get() = field



        public PersistentToken(String owner, String issuer, int amount, UUID linearId, List<PersistentChildToken> listOfPersistentChildTokens) {

            this.owner = owner;

            this.issuer = issuer;

            this.amount = amount;

            this.linearId = linearId;

            this.listOfPersistentChildTokens = listOfPersistentChildTokens;

        }



        // Default constructor required by hibernate.

        public PersistentToken() {

            this.owner = "";

            this.issuer = "";

            this.amount = 0;

            this.linearId = UUID.randomUUID();

            this.listOfPersistentChildTokens = null;

        }



        public String getOwner() {

            return owner;

        }



        public String getIssuer() {

            return issuer;

        }



        public int getAmount() {

            return amount;

        }



        public UUID getLinearId() {

            return linearId;

        }



        public List<PersistentChildToken> getChildTokens() { return listOfPersistentChildTokens; }

    }



    @Entity

    @CordaSerializable

    @Table(name = "token_child_states")

    public static class PersistentChildToken {

        @Id

        private final UUID Id;

        @Column(name = "owner")

        private final String owner;

        @Column(name = "issuer")

        private final String issuer;

        @Column(name = "amount")

        private final int amount;

        @Column(name = "child proof")

        private final String childProof;

        @ManyToOne(targetEntity = PersistentToken.class)

        private final TokenState persistentToken;



        public PersistentChildToken(String owner, String issuer, int amount) {

            this.Id = UUID.randomUUID();

            this.owner = owner;

            this.issuer = issuer;

            this.amount = amount;

            this.persistentToken = null;

            this.childProof = "I am a child";

        }



        // Default constructor required by hibernate.

        public PersistentChildToken() {

            this.Id = UUID.randomUUID();

            this.owner = "";

            this.issuer = "";

            this.amount = 0;

            this.persistentToken = null;

            this.childProof = "I am a child";

        }



        public UUID getId() {

            return Id;

        }



        public String getOwner() {

            return owner;

        }



        public String getIssuer() {

            return issuer;

        }



        public int getAmount() {

            return amount;

        }



        public TokenState getPersistentToken() {

            return persistentToken;

        }

    }

}

令牌发行流程

@InitiatingFlow

@StartableByRPC

public class TokenIssueFlow extends FlowLogic<SignedTransaction> {

    private final Party owner;

    private final int amount;



    public TokenIssueFlow(Party owner, int amount) {

        this.owner = owner;

        this.amount = amount;

    }



    private final ProgressTracker progressTracker = new ProgressTracker();



    @Override

    public ProgressTracker getProgressTracker() {

        return progressTracker;

    }



    @Suspendable

    @Override

    public SignedTransaction call() throws FlowException {

        // We choose our transaction's notary (the notary prevents double-spends).

        Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);

        // We get a reference to our own identity.

        Party issuer = getOurIdentity();



        /* ============================================================================

         *         Create our TokenState to represent on-ledger tokens

         * ===========================================================================*/



        List<TokenSchemaV1.PersistentChildToken> listOfPersistentChildTokens = new ArrayList<>();



        for (int count = 0; count <=5; count++) {

            TokenSchemaV1.PersistentChildToken child = new TokenSchemaV1.PersistentChildToken(owner.getName().toString(), issuer.getName().toString(), amount + 2);

            listOfPersistentChildTokens.add(child);

        }



        // We create our new TokenState.

        TokenState tokenState = new TokenState(issuer, owner, amount, new UniqueIdentifier(), listOfPersistentChildTokens);



        /* ============================================================================

         *      Build our token issuance transaction to update the ledger

         * ===========================================================================*/

        // We build our transaction.

        TransactionBuilder txBuilder = new TransactionBuilder();



        txBuilder.setNotary(notary);



        txBuilder.addOutputState(tokenState, TokenContract.ID);



        TokenContract.Commands.Issue commandData = new TokenContract.Commands.Issue();

        List<PublicKey> requiredSigners = ImmutableList.of(issuer.getOwningKey());

        txBuilder.addCommand(commandData, requiredSigners);



        /* ============================================================================

         *          Write our TokenContract to control token issuance!

         * ===========================================================================*/

        // We sign the transaction with our private key, making it immutable.

        SignedTransaction signedTransaction = getServiceHub().signInitialTransaction(txBuilder);



        // We check our transaction is valid based on its contracts.

        txBuilder.verify(getServiceHub());



        // We get the transaction notarised and recorded automatically by the platform.

        return subFlow(new FinalityFlow(signedTransaction));

    }

}

问题答案:

我怀疑您可能需要在@OneToMany关系上(在父类中)添加一个显式的@Cascade(CascadeType.PERSIST)批注。

看一下下面的工作代码片段:

class SchemaFamily

object TestSchema : MappedSchema(SchemaFamily::class.java, 1, setOf(Parent::class.java, Child::class.java)) {
    @Entity
    @Table(name = "Parents")
    class Parent : PersistentState() {
        @OneToMany(fetch = FetchType.LAZY)
        @JoinColumns(JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"), JoinColumn(name = "output_index", referencedColumnName = "output_index"))
        @OrderColumn
        @Cascade(CascadeType.PERSIST)
        var children: MutableSet<Child> = mutableSetOf()
    }

    @Suppress("unused")
    @Entity
    @Table(name = "Children")
    class Child {
        @Id
        @GeneratedValue
        @Column(name = "child_id", unique = true, nullable = false)
        var childId: Int? = null

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumns(JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"), JoinColumn(name = "output_index", referencedColumnName = "output_index"))
        var parent: Parent? = null
    }
}

请根据以上内容调整您的代码,然后报告。



 类似资料:
  • 本文向大家介绍vuex实现数据状态持久化,包括了vuex实现数据状态持久化的使用技巧和注意事项,需要的朋友参考一下 用过vuex的肯定会有这样一个痛点,就是刷新以后vuex里面存储的state就会被浏览器释放掉,因为我们的state都是存储在内存中的。 所以我们通过 vuex-persistedstate这个插件,来实现将数据存储到本地 用法很简单 1、 2、 以上这篇vuex实现数据状态持久化就

  • 什么是 Volume Volume 就是在一个或者多个容器里有特殊用途的目录。它绕过了容器内部的文件系统为持久化数据、共享数据提供了下面这些有用的特性: 容器可以通过把数据写在 Volume 上来实现数据持久化 Volume 可以在不同的容器之间共享和重用数据 容器数据的备份、恢复和迁移都可以通过 Volume 实现 通过 Volume 实现多容器共享数据,从而实现应用的横向扩展 在 DaoClo

  • 警告:容器被设计为无状态的实例,任何需要持久化的数据,请采用数据库或文件系统保存在容器实例之外,我们不对保存在容器内的数据提供任何保障。当 DaoCloud 需要迁移,或用户扩容容器资源时,容器内的数据将会遗失,并且无法找回。 使用数据库服务 DaoCloud 在服务集成模块中提供了 MySQL、Redis、MongoDB、InfluxDB 等数据服务,如您需要做内容的持久化保存,可以选择使用 M

  • 我在试图通过Kafka流实现以下目标时遇到了一些困难: 在应用程序启动时,(压缩的)主题α被加载到键值StateStore中 Kafka流从另一个主题中消费,使用上面的映射(get),并最终在主题alpha中生成一个新记录 结果是,即使拖缆重新启动,内存中的映射也应与底层主题对齐 我的方法如下: 装载机Treamer(store): : ...但是我得到的是: 试图获取存储处理程序时。 你知道如何

  • 我有一个实体,代表客户发送的订单,这个订单可能会在电话上与客户讨论后更新,但客户发送的初始订单必须保持不更新。我如何可以保持同一实体两次,是否有效的使用深层克隆。我试图分离实体以便持久化上下文持久化一个新的,但是持久化上下文仍然在更新第一个条目。

  • 问题内容: 从这里的讨论看来,Redux reducer的状态应该保留在数据库中。 用户身份验证在这种情况下如何工作? 是否不会创建新的状态对象来替换数据库中先前创建和编辑的每个用户(及其应用程序状态)的先前状态? 在前端使用所有这些数据并不断更新数据库中的状态是否会表现出色? 编辑: 我创建了一个示例Redux auth项目,该项目也恰好示例了通用Redux,并使用Redux,Socket.io