EOS開發中的數據持久性問題(上)

本教程假定你已經完成了EOS開發從智能合約開始c++

要了解數據持久性,請編寫一個簡單的智能合約,做爲地址記錄。雖然這個用例因爲各類緣由而不太適合做爲生產智能合約,但開始學習數據持久性如何在EOSIO上運行而不被與eosio的multi_index功能無關的業務邏輯分心,這也算的上一個很好的合約。shell

第1步:建立一個新目錄

以前,你建立了一個合約目錄,如今就在那裏開始。編程

//shell
cd CONTRACTS_DIR

爲咱們的合約建立一個新目錄並進入目錄:api

//c++
mkdir addressbook
cd addressbook

第2步:建立並打開一個新文件

//c++
touch addressbook.cpp

在你喜歡的編輯器中打開文件。安全

第3步:編寫擴展標準類幷包含EOSIO

在以前的教程中,你建立了一個hello world合約,並學習了基礎知識。你將熟悉下面的結構,該類已分別命名爲addressbook數據結構

//c++

#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
using namespace eosio;

class addressbook : public eosio::contract {
  public:
       
  private: 
  
};

第4步:爲表建立數據結構

在配置和實例化表以前,須要編寫表示地址簿數據結構的結構。 將此視爲「schema」。 因爲它是一個地址簿,該表將包含人,所以建立一個名爲「person」的struct架構

//c++
struct person {};

定義multi_index表的模式時,須要使用惟一值做爲主鍵。編輯器

對於此合約,請使用類型爲account_name的名爲「key」的字段。此合約將爲每一個用戶提供一個惟一條目,所以該密鑰將是基於用戶的account_name保證一致性且有惟一值。函數

//c++
struct person {
    account_name key; 
};

因爲該合約是地址簿,所以可能應該爲每一個條目或人員存儲一些相關的詳細信息。工具

//c++
struct person {
 account_name key;
 string first_name;
 string last_name;
 string street;
 string city;
 string state;
};

ok。基本schema架構現已完成。接下來,定義一個primary_key方法,該方法將由multi_index迭代器使用。每一個multi_index架構都須要一個主鍵。要實現此目的,只需建立一個名爲primary_key()的方法,並返回一個值,在本例中爲結構中定義的成員key

//c++
struct person {
 account_name key;
 string first_name;
 string last_name;
 string street;
 string city;
 string state;
 
 uint64_t primary_key() const { return key; }
};

步驟5:配置多索引表

如今已經使用結構定義了表的模式,咱們須要配置表。須要對eosio::multi_index構造函數進行命名和配置,以使用咱們以前定義的結構。

//c++
typedef eosio::multi_index<N(people), person> address_index;
  • 咱們把N(N(base32 X),用於從X的base32編碼的字符串解釋生成編譯時uint64_t)命名爲表。該表包含許多不一樣的個體「persons」,所以將表命名爲「people」。
  • 傳入上一步中定義的單person結構
  • 聲明此表的類型。此類型將用於稍後實例化此表。
//c++
//configure the table
typedef eosio::multi_index<N(people), person> address_index;

使用上述multi_index配置,有一個名爲peoplemulti_index表,該表基於使用struct person的該表的單個行的模式或數據結構。

到目前爲止,咱們的文件應該是這樣的。

//c++

#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>

using namespace eosio;

class addressbook : public eosio::contract {

  public:

  private:
    struct [[eosio::table]] person {
      account_name key;
      std::string first_name;
      std::string last_name;
      std::string street;
      std::string city;
      std::string state;

      uint64_t primary_key() const { return key; }
    };

    typedef eosio::multi_index<N(people), person> address_index;

};

第6步:構造函數

使用C++類時,你應該建立的第一個公共方法是構造函數。

咱們的構造函數將負責最初設置合約。

EOSIO合約擴展了合約類。使用合約範圍初始化咱們的父合約類。咱們的構造函數傳遞的範圍參數是正在部署合約的區塊鏈上的賬戶。

//c++
addressbook(account_name self): contract(self){}

第7步:向表中添加記錄

之前,多索引表的主鍵被定義爲強制執行此合約將僅爲每一個用戶存儲一條記錄。爲了使其所有工做,須要創建一些關於設計的假設。

  • 受權修改通信簿的惟一賬戶是用戶。
  • 咱們表的primary_key是惟一的,基於用戶名。
  • 對於可用性,合約應該可以經過單個操做建立和修改錶行。

在eosio中,區塊鏈具備惟一的賬戶,所以在此特定用例中,account_name是做爲primary_key的理想候選者。account_name類型是uint64_t

接下來,爲用戶定義添加或更新記錄的操做。此操做須要接受此操做須要可以放置(建立)或修改的任何值。

格式化定義以使其更容易閱讀。爲了簡化用戶體驗和界面,有一個方法負責建立和修改行。所以,將其命名爲「upsert」,即「update」和「insert」的組合。

//c++

void upsert(
  account_name user, 
  std::string first_name, 
  std::string last_name, 
  std::string street, 
  std::string city, 
  std::string state
) {}

早些時候,有人提到只有用戶才能控制本身的記錄,由於這個合約是選擇加入的。爲此,請使用eosio.cdt提供的require_auth方法。此方法接受一個參數,即account_name類型,並斷言執行交易的賬戶等於提供的值。

//c++
void upsert(account_name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state) {
  require_auth( user );
}

實例化表。以前,配置了multi_index表,並將其聲明爲address_index。要實例化一個表,請考慮這兩個必需參數:

  • 「code」,表明合約的賬戶。能夠經過做用域_self變量訪問此值。
  • 定義合約付款人的範圍「scope」,該用例中的合約負責支付ram費用。
//c++
void upsert(account_name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state) {
  require_auth( user );
  address_index addresses(_self, _self );
}

接下來,查詢迭代器,將其設置爲變量,由於此迭代器將被屢次使用。

//c++
void upsert(account_name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state) {
  require_auth( user );
  address_index addresses(_self, _self );
  auto iterator = addresses.find(user);
}

安全性已經創建而且表格實例化了,太棒了!

接下來,編寫用於建立或修改表的邏輯。檢測特定用戶是否已存在。

爲此,請經過傳遞user參數來使用表的find方法。find方法將返回一個迭代器。使用該迭代器對end方法進行測試。end方法是「null」的別名。

//c++
void upsert(account_name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state) {
  require_auth( user );
  auto iterator = addresses.find( user );
  address_index addresses(_self, _self );
  if( addresses.find( user ) == addresses.end() )
  {
    //The user isn't in the table
  }
  else {
    //The user is in the table
  }
}

使用multi_index方法emplace在表中建立記錄。此方法接受兩個參數,即此記錄的範圍「scope」和回調函數。

emplace方法的回調函數必須使用lamba來建立接口。在body中分配行的值和提供給upsert的值。

//c++
void upsert(account_name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state) {
  require_auth( user );
  address_index addresses(_self, _self );
  auto iterator = addresses.find( user );
  if( iterator == addresses.end() )
  {
        addresses.emplace(user, [&]( auto& row ) {
      row.key = user;
      row.first_name = first_name;
      row.last_name = last_name;
      row.street = street;
      row.city = city;
      row.state = state;
    });
  }
  else {
    //The user is in the table
  }
}

接下來,處理「upsert」函數的修改或更新。使用modify方法,傳遞一些參數

  • 前面定義的迭代器,在調用此操做時設置爲聲明的用戶。
  • 範圍「scope」或「ram payer」ram消費者,在這種狀況下是用戶,如先前在提出該合約的設計時所決定的那樣。
  • 回調函數用於處理表的修改。
//c++
void upsert(account_name user, std::string first_name, std::string last_name, std::string street, std::string city, std::string state) {
  require_auth( user );
  address_index addresses(_self, _self );
  auto iterator = addresses.find( user );
  if( iterator == addresses.end() )
  {
   addresses.emplace(user, [&]( auto& row ) {
     row.key = user;
     row.first_name = first_name;
     row.last_name = last_name;
     row.street = street;
     row.city = city;
     row.state = state;
   });
  }
  else {
   addresses.modify(iterator, user, [&]( auto& row ) {
     row.first_name = first_name;
     row.last_name = last_name;
     row.street = street;
     row.city = city;
     row.state = state;
   });
  }
}

地址簿合約如今具備一個功能操做,若是該記錄尚不存在,將容許用戶在表中建立一行,若是已存在則修改它。

可是若是用戶想要徹底刪除記錄呢?請看EOS的數據持久性(下)

對了,文中調用的各類eos方法能夠參考EOS.IO C語言API手冊

======================================================================

分享一個交互式的在線編程實戰,EOS智能合約與DApp開發入門

EOS教程

本課程幫助你快速入門EOS區塊鏈去中心化應用的開發,內容涵蓋EOS工具鏈、帳戶與錢包、發行代幣、智能合約開發與部署、使用代碼與智能合約交互等核心知識點,最後綜合運用各知識點完成一個便籤DApp的開發。

匯智網原創翻譯,轉載請標明出處。這裏是原文

相關文章
相關標籤/搜索