我有一些类似的SQL查询,所有选中的字段都相同,只是条件不同。因此,结果集处理程序也是相同的。我使用sqlite3和sqlite_modern_cpp。
以下是两个类似的功能(还有其他几个):
QVariantMap getItemById(int id) {
QVariantMap map;
database db(dbfile);
db << "select id,name,price,qty from items where id=?"
<< id
>> [&] (int id, std::string name, double price, int qty) {
map.insert("id", id);
map.insert("name", QString::fromStdString(name));
map.insert("price", price);
map.insert("qty", qty);
};
return map;
}
QVariantMap getItemByCatAndSeq(int cat, int seq) {
QVariantMap map;
database db(dbfile);
db << "select id,name,price,qty from items where cat=? and seq=?"
<< cat << seq
>> [&] (int id, std::string name, double price, int qty) {
map.insert("id", id);
map.insert("name", QString::fromStdString(name));
map.insert("price", price);
map.insert("qty", qty);
};
return map;
}
您看,查询中的所有字段都是“id,name,price,qty”,结果集处理程序也是相同的。
一个结果集处理程序应该足够了,但我必须在每个函数中复制并粘贴相同的代码。此外,所选字段的名称和顺序必须与参数resultset handler - lambda function。
匹配如何消除这种重复的代码?有更好的解决方案吗?提前谢谢。
修改
我尝试了仿函数方法,如下所示:
struct ItemResultHandler {
explicit ItemResultHandler(QVariantMap& map_) : map(map_) {}
void operator() ( int id, std::string name, double price, int qty ) {
map.insert("id", id);
map.insert("name", QString::fromStdString(name));
map.insert("price", price);
map.insert("qty", qty);
}
QVariantMap& map;
};
以上两个类似的功能之一将改为:
QVariantMap getItemById(int id) {
QVariantMap map;
database db(dbfile);
db << "select id,name,price,qty from items where id=?"
<< id
>> ItemResultHandler(map);
return map;
}
但是,它有编译错误:
../../myapp/src/utility/function_traits.h:12: error: type 'void (ItemResultHandler::*)(std::__1::basic_string<char>, std::__1::basic_string<char>, int, int)' cannot be used prior to '::' because it has no members
decltype(&Function::operator())
^
../../myapp/src/sqlite_modern_cpp.h:218: error: incomplete definition of type 'sqlite::utility::function_traits<ItemResultHandler>'
binder<traits::arity>::run(*this, func);
~~~~~~^~
答案 0 :(得分:1)
映射我们处理的所有不同结果类型的问题。所以模板有点复杂,看起来它不处理这种情况。
以下是如何使用类型扩展来完成此操作的示例。
// The thing you want
struct Item {
int id;
string name;
double price;
int qty;
};
// to get it back we need to give a deserialization method:
namespace sqlite {
template<> void get_col_from_db(database_binder& db, int inx, ::Item*& ret) { // specify the type it will be used on, a pointer is necessary if you’re type has no default constructor. Otherwise a object ref does the job too.
ret = new Item();
get_col_from_db(db, inx++, ret->id);
get_col_from_db(db, inx++, ret->name);
get_col_from_db(db, inx++, ret->price);
get_col_from_db(db, inx++, ret->qty);
}
}
{// usage
Item* item;
db << "select val,name,price,qty from test" >> item;
std::cout << item->name;
delete item;
}
但这很丑陋,肯定需要改变,我将在下一版本中摆脱这个指针混乱。
然而有一个更短的版本,只需用这种方式将你的仿函数转换为lambda,用你的结构替换你的QMap:
auto ItemResultHandler = [](Item& item) -> std::function<void(int, std::string , double , int )> {
return [&item](int id, std::string name, double price, int qty) mutable {
item.id = id;
item.name = name;
item.price = price;
item.qty = qty;
};
};
只需像这样使用它:
Item item;
db << "select val,name,price,qty from test" >> ItemResultHandler(item);