上一章咱们学习了对智能合约开发来讲相当重要的第一步:c++
- 知道了RAM、multi_index和EOS数据库各是什么以及它们之间的关系;
- 知道了multi_index是内存数据库的入口;
- 了解了multi_index内部的结构长什么样子;
今天这章,主要介绍multi_index的相关操做,趁机巩固一波上一章学习到的理论知识。数据库
上一章说到multi_index的概念——多索引容器,multi_index容器的内部结构能够类比成传统数据库里的一张表,只不过这张表只有一列,每一行都是一个struct结构体。dom
这一章就要向你们介绍,如何具体使用multi_index。函数
仍是上一章中的例子:学习
multi_index的容器(表)里每一行都是上面的struct
结构体,而且都是按照主键升序排列。因此每个multi_index中会有一个默认索引,也就是主键。如上图,就是按照主键(pkey)升序排列的。ui
uint64_t primary_key() const { return pkey; }
通常而言,在struct
结构体中会声明一行得到主键的方法primary_key()
,这里定义了主键类型为uint64_t
,返回结构体中的pkey
字段,即pkey
这个字段就是整个结构体的主键。spa
既然叫multi_index,确定不仅能够根据主键进行索引,事实上,咱们还能够自定义索引。例如能够在结构体中定义以下方法:code
account_name get_customer() const { return customer; }
这就是咱们自定义的索引。仿照以前的primary_key()
能够看到,这个方法返回值的类型为account_name
,返回的字段为customer
。固然自定义的索引并不必定要返回结构体中的某个字段的变量,也能够将变量之间的运算结果做为索引。blog
这里先贴上结构体的完整表达,方便下面介绍如何使用多索引:索引
struct service_struct { uint64_t pkey; account_name customer; Date date; uint32_t odometer; auto primary_key() const {return pkey;} account_name get_customer() const {return customer;} EOSLIB_SERIALIZE(service_struct,( pkey )( customer )( date )( odometer )) } typedef eosio::multi_index<service, service_struct, index_by<N(bycustomer), const_mem_fun<service_struct,account_name, &service_struct::get_customer> > > customer_index;
解释一下,使用上面的方式来定义索引,eosio::multi_index<...>
的参数解释以下:
service
: multi_index容器的表名(如上图)service_struct
: 智能合约重定义的struct结构体名称,也能够理解成表中的一行记录;indexed_by<...>
:
N(bycustomer)
: 给索引发个名字 - bycustomerconst_mem_fun<...>
:
account_name
: 索引的类型&service_struct::get_customer
:经过service_struct
结构体中的get_customer
函数得到(索引)经过上述表达,就能够再生成一张按customer
为索引的表bycustomer
(见本文第一张图)。左边是按照主键索引的原表service
,右边的表就是咱们按照customer
的索引生成的新表(按customer从小到大进行排列),能够看到新表内的行内容和以前是一行的(见虚线指向原表),只不过按照customer字段进行了从新排列。
这里定义了customer_index类型,这样之后就能够直接用这个类型去初始化真正的multi_index表。
上一章咱们介绍过迭代器,能够把迭代器想象成一个电梯,经过在索引中上下滑动来定位数据。接着上面介绍的自定义索引comstomer_index:
account_name customer_acct = eosio::chain::string_to_name(customer_name); auto cust_itr = customer_index.find(customer_acct);
经过上述代码,咱们就能够找到bycustomer
表中,customer为某个特定值的全部行(结构体)了。好比,第一张图中,若是传入的参数为"bob",那就能够找出全部customer为bob的数据了,放入迭代器里。经过迭代器就能够逐条获取咱们想要的数据信息。
获得了迭代器以后,我们再来看看怎么使用迭代器:
while(cust_itr != service.end() && cust_itr -> customer == customer_acct) { // code to execute cust_itr++; }
其中cust_itr != service.end()
表示迭代器并无走到service表的结尾,&&
以后也很容易看懂,再筛选customer的值。每次小的遍历结束是,迭代器+1,表示继续访问迭代器中的下一行。
经过上面的介绍,你们应该就能够理清multi_index和迭代器是如何配合工做的:
i经过multi_index能够获得一张按照特定字段索引的表,再经过对索引设置一些条件,就能够筛选获得一些迭代器,再经过对迭代器的遍历,就能够访问咱们想要访问的数据了。
上文关于multi_index多与定义有关,如今终于要开始实例化multi_index了。
multi_index(uint64_t code, uint64_t scope)
在上面的初始化(实例化)的语句中,能够看到有两个参数:
这里的code和scope,都是用来为表创建访问权限的。
因此要想初始化上面的customer_index
,可使用:
// customer_index 就是以前 typedef 定义的类型 // bycustomer就是新表 // _self就是当前调用方法的帐户 customer_index bycustomer(_self, _self);
这里顺便说一下find
,multi_index使用.find
来查询,代码接上往下写:
void demo::create(const uint64_t id, const account_name cust_acct, const Date date, const uint32_t odometer) { // 找出特定值的customer的数据 // 这里的auto至关于其余语言中的var,声明变量时不指定类型 auto itr = bycustomer.find(cust_acct); // 查询customer = cust_acct的记录并要求该记录不存在 // 由于primary_key不能重复 // 因此插数据以前先查询一下,保证不重复 eosio_assert(itr == profile.end(), "Account already exists"); // 往索引里添加记录 bycustomer.emplace(cust_acct, [&](auto& c)) { c.pkey = id; c.customer = cust_acct; c.date = date; c.odometer = odometer; } }
其中[&](auto& c)
是c11以后一种新的lambda表达式,有兴趣的同窗能够自行深刻了解,这里简单介绍一下,这个表达式大概表示:
除了该函数已有的参数,其余的参数例如 id, date, odometer这些,都是在上层的做用域中经过引用的形式传入函数内。其中auto咱们以前说过,表示不限制类型,可是也为引用。
看懂了添加记录,其余诸如删、改、查的操做也就不难看懂了,你们能够去官网查看相关例子:
https://eosio-cpp.readme.io/d...
本章咱们学习了:
但愿你们学完以后能够去官网继续补充删、改、查的相关例子,以达到触类旁通的效果。下面几篇咱们将正式了解EOS智能合约开发的二三事。