---
# System prepended metadata

title: EOS-多索引表使用指南
tags: [区块链, DAPP, 智能合约, EOS]

---

# 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" );
          }
       }
    }
