今天群内讨论较多的内容为数据表的查询,集中在两个问题上:
为什么我的数据表查出来是个空的?
针对这两个问题简单的给出答案就是:
基于eos进行智能合约开发时的abi注释要规范
数据表查询为空解决方案
仍旧以前文中的智能合约为例,在结构体声明及Multi-Index定义的时候要规范,且注释要准确,代码如下:
private:
2 account_name _this_contract;
3 // @abi table heros i64
4 struct heros
5 {
6 uint64_t heroid; //天龙英雄的id
8 string heroname; //天龙英雄的名字
9 string herodes; //天龙英雄的个人描述
10 string heroborn; //天龙英雄的出生地
11 uint64_t heroforceidx; //天龙英雄的武力值
12 uint64_t heroinsideidx; //天龙英雄的内力值
13
14 uint64_t primary_key() const{return heroid;}
15 //等等,不再赘述
16
17 EOSLIB_SERIALIZE(heros,(heroid)(heroname)(herodes)(heroborn)(heroforceidx)(heroinsideidx))
18 };
19 typedef eosio::multi_index>> heros_table;
20 heros_table ht;
在这里我们生命了一个结构体heros,同时将结构体中的各个变量使用EOSLIB_SERIALIZE序列化,然后使用multi-index定义一个数据表heros_table(此处添加了二级索引,本文关注点不在此)。在我们平时的开发过程中,只是中的内容是对最终的实现效果影响不大的,而在eos智能合约开发的过程中,如果需要查询由multi-index生成的数据表中的内容,就要严格注意注释的使用。
此处的注释
// @abi table heros i64
以及multi-index的定义的表名
eosio::multi_index>> heros_table;
三者尽量保持一致,这样方便进行查询。当然没有注释的情况下,通过代码跟踪我们可以发现,数据也是可以写入到chainbase中,只不过使用命令行进行查询的时候查询结果为空。正常的查询结果如下:
1//查询表命令行,记得对应【合约】、【谁为这张表支付RAM的账户】、【表名】
2cleos get table tlbb.code tlbb.code heros
3//查询结果
4{
5 "rows": [{
6 "heroid": 0,
7 "heroname": "",
8 "herodes": "丐帮帮主",
9 "heroborn": "辽国",
10 "heroforceidx": 1000,
11 "heroinsideidx": 500
12 },
13 //等等内容
14}
而如果注释不存在或者注释的表名不一致的则会出现如该合约中本表不存在或者说查出的结果是空的现象,基于此我们在智能合约的书写过程中,abi的生成还是重要的,尽管不会影响数据的写入操作或者action的执行操作,但如果没有规范的注释使用命令行查询或者调用RPC接口将会出现问题。
查询某数据表中的数据总量
在使用命令行查询数据表中的数据的时候,对查询的总量是做了限制的,我们在cleos的main.cpp中可以看出默认返回数据设置了限制,也就是不管我们查询的表中有多少数据,最多展示10个,其他的可以通过lower或者upper的方式展示:
1//查询表命令行,记得对应【合约】、【合约账户】、【表名】
2cleos get table tlbb.code tlbb.code heros
3//get table中关于limit的说明
4uint32_t limit = 10;
5getTable->add_option( "-l,--limit", limit, localized("The maximum number of rows to return") );
对于有分页需求的开发者来讲,表中一共存在有多少数据对他们来说是至关重要的,那么我们是否可以尝试获取到表中的数据总量呢?我们可以看到在遍历的过程中,如果数据量达到了limit的限制,则会跳出整个遍历过程,也就是查询结果中的数据量是受限于limit的值的:
1 for (; itr != upper; ++itr)
2{
3 copy_inline_row(*itr, data);
4 if (p.json)
5 {
6 result.rows.emplace_back(abis.binary_to_variant(abis.get_table_type(p.table), data, abi_serializer_max_time));
7 } else
8 {
9 result.rows.emplace_back(fc::variant(data));
10 }
11 if (++count == p.limit || fc::time_point::now() > end)
12 {
13 break;
14 }
15}
我们在查询数据表返回值的结构体加上一个字段来统计数据表中的总数据量,并在这个遍历的过程中使用自增的方式来统计从lower到upper的总值,即可得出总的数据量:
1//数据表查询返回值结构体
2struct get_table_rows_result
3{
4 vector rows; ///< one row per item, either encoded as hex String or JSON object
5 uint64_t totalRows; ///<统计总的数据量
6 bool more = false; ///< true if last element in data is not the end and sizeof data() < limit
7};
8//统计数据表中数据的总量
9for (; itr != upper; ++itr)
10{
11 result.totalRows++;
12}
13//切记,该结构的FC映射也要加入该变量的映射
14FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_result, (rows)(more)(totalRows) );
15//在cleos查询表数据的时候,加上以下打印
16auto res = result.as();
17auto totalRows = res.totalRows;
18std::cout << "Total Row is:"<
经过以下步骤,再次执行命令行来查询数据表,便可获得这张表中的数据总量,本次查询返回的数据量,以及数据的具体信息:
数据表查询返回值结构体中加入统计总量的参数。
FC_REFLECT加入新的变量的映射。
查询时以自增的方式来统计总量。
cleos命令行加相关打印进行观察。
再次执行上面的命令行,返回的结果如下:
1cleos get table tlbb.code tlbb.code heros
2Total Row is:17
3Get Total Row is:10
4{
5 "rows": [{
6 "heroid": 0,
7 "heroname": "",
8 "herodes": "丐帮帮主",
9 "heroborn": "辽国",
10 "heroforceidx": 1000,
11 "heroinsideidx": 500
12 },
13 //等等,更多的数据
14 "more": true,
15 "totalRows": 17
16}
也就是这张表中共有17条数据,而本次查询结果只返回了10条,也可以看到more为true代表着有更多信息等待展示。
本文从群内朋友提出的问题出发,介绍了智能合约开发中注释的规范使用,以及如何通过修改代码的方式来获取某张表中数据的总量,当然这是在本地测试节点下完成的,使用主网的过程中,这些代码我们是无法做出更改的。
如果你觉得我的文章对你有一定的帮助,请点击文章末尾的喜欢该作者。
如果你对eos开发感兴趣,欢迎关注本公众号,一起学习eos开发。
image
微信公众号
有任何疑问或者指教请添加本人个人微信,当然有对eos开发感兴趣或者金庸粉的也可以添加一起交流,备注eos开发或金庸。
image
个人微信号