# EOS-多索引表使用指南 --- * 简介 EOSIO Multi-Index API为EOSIO数据库提供C ++接口。源码文件路径:eos/contracts/eosiolib/multi_index.hpp。其内部使用的是 C 的 Ddatabase_api 来操作数据库,文件路径:eos/contracts/eosiolib/wasm_interface.cpp。表对象的创建和修改都需要花费RAM,删除则会返回RAM到账户中。 * 命名规则 | 结构名称 | 解释说明 | | -------- | -------- | | 合约帐号名称 | 只能包含字符.abcdefghijklmnopqrstuvwxyz12345。a-z(小写)1-5和.(之间)必须是12个字符 | | 表名 | 最多只能包含12个字母字符 | | 结构 | 最多只能包含12个字母字符 | | 代币符号 | 必须是A和Z之间的大写字母字符必须是7个字符或更少| * 使用教程 定义存储结构 创建一个 EOSIO Multi-Index 表必需要一个uint64_t 主键。为了使表能够检索主键,存储在表中的对象需要具有名为 primary_key() 的 const 成员函数,该函数返回 uint64_t 。EOSIO Multi-Index表还支持最多16个二级索引.索引支持的格式如下: - uint64_t - uint128_t - uint256_t - double - long double **1.创建表** typedef eosio::multi_index<N(TableName), T,...Indices> table_name(code,scope); | 参数 | 参数说明 | | -------- | -------- | | TableName | 表的名称 | | T | 表中存储的数据类型 | | Indices | 表的二级索引,此处支持最多16个索引 | | code | 拥有表的帐户 | | scope | 数据所属的账户 | | table_name | 存在在内存中的表名称 | scope 负责新对象的存储使用,如果必须创建表(和二级索引表),则 scope 支付表创建的 RAM 开销。 **2.表的操作** * 按二级索引排序 ``` auto expidx = orders.get_index<N(byexp)>(); print("Items sorted by expiration:\n"); for( const auto& item : expidx ) { print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); } ``` * 添加多索引表(emplace) 添加一个新的对象到表中 orders.emplace( payer, [&]( auto& o ) { o.id = 1; o.expiration = 300; o.owner = N(dan); }); | 参数 | 说明 | | -------- | -------- | | payer | 付款账号消耗RAM | | constructor | 用于对要在表中创建的对象进行就地初始化返回值| 返回值:新创建的对象的主键迭代器 * 更新多索引表(modify) 在Multi-Index表中创建一个新对象,该对象具有唯一的主键(在对象中指定)。该对象被序列化并写入表中。如果该表不存在,则创建该表。付款人负责新对象的存储使用,如果必须创建表(和二级索引表),则为表创建的开销。更新辅助索引以引用新添加的对象。如果辅助索引表不存在,则创建它们。更新多索引表(modify)在表中修改一个已经存在的对象 ``` print("Modifying expiration of order with ID=2 to 400.\n"); orders.modify( order2, payer, [&]( auto& o ) { o.expiration = 400; }); ``` | 参数 | 说明 | | -------- | -------- | | order2 | 指向要更新的对象的迭代器 | | payer | 更新行的存储使用情况的付款人的帐户名称 | | updater | 更新目标对象的lambda 函数 | 已修改的对象已序列化,然后替换表中的现有对象。 付款人需要为更新对象的存储使用付费。 如果付款人与现有付款人相同,则付款人仅支付现有和更新对象之间的使用差异(如果此差异为负,则退款)。 如果付款人与现有付款人不同,则现有付款人将退还现有对象的存储使用情况。 无返回值 * erase(删) 使用主键删除一个表中已经存在的对象 addresses.erase(itr); | 参数| 说明 | | -------- | -------- | | itr | 指向要删除的对象的迭代器 | 该对象将从表中删除,并回收所有关联的存储。 对于对象的存储使用的现有支付者,删除的对象的表和二级索引使用,以及如果移除表和索 引,相关的开销将退还。在删除所有行后,表将自动删除。 返回: 返回指向删除对象后面的对象的指针。 * find(查) 在表中根据主键查找已经存在的对象 auto itr = addresses.find(N(dan)); | 参数| 说明 | | -------- | -------- | | primary | 对象的主键值 | 返回值:返回一个查询到的对象的迭代器; 如果没有查询到指定对象,返回一个end迭代器。 ###### tags: `区块链` `EOS` `DAPP` `智能合约` * 例子 ```c++ #include <eosiolib/eosio.hpp> #include <eosiolib/dispatcher.hpp> #include <eosiolib/multi_index.hpp> using namespace eosio; namespace limit_order_table { //定义结构体 struct limit_order { uint64_t id; uint128_t price; uint64_t expiration; account_name owner; auto primary_key() const { return id; } uint64_t get_expiration() const { return expiration; } uint128_t get_price() const { return price; } EOSLIB_SERIALIZE( limit_order, ( id )( price )( expiration )( owner ) ) }; class limit_order_table { public: ACTION( N( limitorders ), issue_limit_order ) { EOSLIB_SERIALIZE( issue_limit_order ) }; //定义合同方法 static void on( const issue_limit_order& ilm ) { //获得表的归属者 auto payer = ilm.get_account(); print("Creating multi index table 'orders'.\n"); //实例化表 eosio::multi_index< N( orders ), limit_order, indexed_by< N( byexp ), const_mem_fun< limit_order, uint64_t, &limit_order::get_expiration> >, indexed_by< N( byprice ), const_mem_fun< limit_order, uint128_t, &limit_order::get_price> > > orders( N( limitorders ), N( limitorders ) ); //添加多索引表 orders.emplace( payer, [&]( auto& o ) { o.id = 1; o.expiration = 300; o.owner = N(dan); }); auto order2 = orders.emplace( payer, [&]( auto& o ) { o.id = 2; o.expiration = 200; o.owner = N(thomas); }); //主键排序 print("Items sorted by primary key:\n"); for( const auto& item : orders ) { print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); } auto expidx = orders.get_index<N(byexp)>(); //索引排序 print("Items sorted by expiration:\n"); for( const auto& item : expidx ) { print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); } auto pridx = orders.get_index<N(byprice)>(); print("Items sorted by price:\n"); for( const auto& item : pridx ) { print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); } print("Modifying expiration of order with ID=2 to 400.\n"); //修改 orders.modify( order2, payer, [&]( auto& o ) { o.expiration = 400; }); //获得主键大于100的实例 auto lower = expidx.lower_bound(100); print("First order with an expiration of at least 100 has ID=", lower->id, " and expiration=", lower->get_expiration(), "\n"); }; } /// limit_order_table namespace limit_order_table { extern "C" { /// 执行合同下任何方法都需要先经过此方法 void apply( uint64_t code, uint64_t action ) { require_auth( code ); eosio_assert( eosio::dispatch< limit_order_table, limit_order_table::issue_limit_order >( code, action ), "Could not dispatch" ); } } }