如何使用一个结果集处理程序消除多个类似的sql查询

How to eliminate multiple similar sql queries with one resultset handler?

本文关键字:sql 程序 查询 处理 何使用 一个 结果      更新时间:2023-10-16

我有一些类似的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);
                               ~~~~~~^~

映射我们处理的所有不同结果类型是一个问题。因此,模板变得有点复杂,看起来它不处理这种情况。

下面是一个如何使用类型扩展的示例。

// 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);