如何通过 Poco::Data 从数据库读取值(可能为 NULL)到 std::vector?
How to read values (possibly NULL) from database into std::vector via Poco::Data?
我想从 SQL-Server 数据库中读取许多行(值可能为 NULL)到 std::vector
。读取单个值 NULL 和非 NULL 都有效。但是我在读取多个值时遇到问题。
根据 POCO Data User Guide,我想出了以下代码:
之前的样板代码:
Poco::Data::ODBC::Connector::registerConnector();
Poco::Data::Session session("ODBC", makeConnectionString());
Poco::Data::Statement select(session);
代码ok,读取单个值:
// note initialization here: otherwise ODBCHandleException will be thrown on non-NULL-value
Poco::Nullable<std::string> n = std::string("");
select << "SELECT col_name FROM table_name WHERE id=6;", into(n);
select.execute();
代码不正常,读取多个值,抛出Poco::Data::ODBC::HandleException
:
// how to initialize here?
std::vector<Poco::Nullable<std::string>> ns;
select << "SELECT col_name FROM table_name;", into(ns);
select.execute(); // <- error thrown here
有什么可以修复我的代码的建议吗?
尝试了很多方法。最后我用 Poco::Data::RecordSet
替换了 std::vector
。现在我可以遍历它的 Poco::Data::Row
s,这反过来又给我输入了 Poco::Dynamic::Var
的列值。这里 Poco::Dynamic::Var::isEmpty()
让我检查数据库条目是否为 NULL。
请参阅简化的代码进行说明:
Poco::Data::ODBC::Connector::registerConnector();
Poco::Data::Session session("ODBC", makeConnectionString());
Poco::Data::Statement select(session);
select << "SELECT col_name FROM table_name";
select.execute();
Poco::Data::RecordSet rows(select); // use Recordset here instead of vector...
std::vector<std::string> beans; // ...and convert it to vector...
auto convert = [&](Poco::Data::Row row) // ...with this lambda function.
{
const Poco::Dynamic::Var var = row["col_name"];
if (var.isEmpty()) // convert NULL values to empty string
return std::string("");
return var.convert<std::string>();
};
std::transform(rows.begin(), rows.end(), std::back_inserter(beans), convert);
for (const auto& b : beans)
std::cout << b << std::endl;
好的是,它可以扩展到 更复杂的 版本(如果您非常感兴趣,请阅读):
class GenericTableManager
{
public:
GenericTableManager(Poco::Data::Session& session, const std::string& tableName);
template <class T_Bean>
std::vector<T_Bean> selectAll(std::function<T_Bean(Poco::Data::Row)> convert) const
{
Poco::Data::Statement select(m_session);
select << "SELECT * FROM " << m_tableName;
select.execute();
Poco::Data::RecordSet rows(select);
std::vector<T_Bean> beans;
std::transform(rows.begin(), rows.end(), std::back_inserter(beans), convert);
return beans;
}
template <class T_Bean>
size_t insert(
const T_Bean& bean,
std::function<Poco::Data::Row(const T_Bean&)> convert) const
{
const Poco::Data::Row row = convert(bean);
Poco::Data::Statement stmt(m_session);
stmt << "INSERT INTO " << m_tableName
<< " (" << StringUtil::join(*row.names()) << ") "
<< "VALUES (" << placeholders(row.fieldCount()) << ")";
for (const auto& value : row.values())
stmt.addBind(Poco::Data::Keywords::bind(value));
return stmt.execute();
}
private:
Poco::Data::Session& m_session;
const std::string m_tableName;
static std::string placeholders(const size_t n);
};
// on caller side:
// once you have your ORM converters set up...
auto convertOOtoR = [](const MyBean& bean) -> Poco::Data::Row {
Poco::Data::Row row;
row.append("myattr1", bean.myattr1);
row.append("myattr2", bean.myattr2);
return row;
};
auto convertRtoOO = [](Poco::Data::Row row) -> MyBean{
MyBean bean;
Poco::Dynamic::Var var = row["myattr1"];
bean.myattr1 = var.isEmpty() ? "" : var.convert<std::string>();
// ...
return bean;
};
// ...the SQL part boils down to a oneliner
GenericTableManager tm(session, "mytablename");
tm.insert<MyBean>(createMyBean(), convertOOtoR);
std::vector<MyBean> beans = tm.selectAll<MyBean>(convertRtoOO);
我想从 SQL-Server 数据库中读取许多行(值可能为 NULL)到 std::vector
。读取单个值 NULL 和非 NULL 都有效。但是我在读取多个值时遇到问题。
根据 POCO Data User Guide,我想出了以下代码:
之前的样板代码:
Poco::Data::ODBC::Connector::registerConnector();
Poco::Data::Session session("ODBC", makeConnectionString());
Poco::Data::Statement select(session);
代码ok,读取单个值:
// note initialization here: otherwise ODBCHandleException will be thrown on non-NULL-value
Poco::Nullable<std::string> n = std::string("");
select << "SELECT col_name FROM table_name WHERE id=6;", into(n);
select.execute();
代码不正常,读取多个值,抛出Poco::Data::ODBC::HandleException
:
// how to initialize here?
std::vector<Poco::Nullable<std::string>> ns;
select << "SELECT col_name FROM table_name;", into(ns);
select.execute(); // <- error thrown here
有什么可以修复我的代码的建议吗?
尝试了很多方法。最后我用 Poco::Data::RecordSet
替换了 std::vector
。现在我可以遍历它的 Poco::Data::Row
s,这反过来又给我输入了 Poco::Dynamic::Var
的列值。这里 Poco::Dynamic::Var::isEmpty()
让我检查数据库条目是否为 NULL。
请参阅简化的代码进行说明:
Poco::Data::ODBC::Connector::registerConnector();
Poco::Data::Session session("ODBC", makeConnectionString());
Poco::Data::Statement select(session);
select << "SELECT col_name FROM table_name";
select.execute();
Poco::Data::RecordSet rows(select); // use Recordset here instead of vector...
std::vector<std::string> beans; // ...and convert it to vector...
auto convert = [&](Poco::Data::Row row) // ...with this lambda function.
{
const Poco::Dynamic::Var var = row["col_name"];
if (var.isEmpty()) // convert NULL values to empty string
return std::string("");
return var.convert<std::string>();
};
std::transform(rows.begin(), rows.end(), std::back_inserter(beans), convert);
for (const auto& b : beans)
std::cout << b << std::endl;
好的是,它可以扩展到 更复杂的 版本(如果您非常感兴趣,请阅读):
class GenericTableManager
{
public:
GenericTableManager(Poco::Data::Session& session, const std::string& tableName);
template <class T_Bean>
std::vector<T_Bean> selectAll(std::function<T_Bean(Poco::Data::Row)> convert) const
{
Poco::Data::Statement select(m_session);
select << "SELECT * FROM " << m_tableName;
select.execute();
Poco::Data::RecordSet rows(select);
std::vector<T_Bean> beans;
std::transform(rows.begin(), rows.end(), std::back_inserter(beans), convert);
return beans;
}
template <class T_Bean>
size_t insert(
const T_Bean& bean,
std::function<Poco::Data::Row(const T_Bean&)> convert) const
{
const Poco::Data::Row row = convert(bean);
Poco::Data::Statement stmt(m_session);
stmt << "INSERT INTO " << m_tableName
<< " (" << StringUtil::join(*row.names()) << ") "
<< "VALUES (" << placeholders(row.fieldCount()) << ")";
for (const auto& value : row.values())
stmt.addBind(Poco::Data::Keywords::bind(value));
return stmt.execute();
}
private:
Poco::Data::Session& m_session;
const std::string m_tableName;
static std::string placeholders(const size_t n);
};
// on caller side:
// once you have your ORM converters set up...
auto convertOOtoR = [](const MyBean& bean) -> Poco::Data::Row {
Poco::Data::Row row;
row.append("myattr1", bean.myattr1);
row.append("myattr2", bean.myattr2);
return row;
};
auto convertRtoOO = [](Poco::Data::Row row) -> MyBean{
MyBean bean;
Poco::Dynamic::Var var = row["myattr1"];
bean.myattr1 = var.isEmpty() ? "" : var.convert<std::string>();
// ...
return bean;
};
// ...the SQL part boils down to a oneliner
GenericTableManager tm(session, "mytablename");
tm.insert<MyBean>(createMyBean(), convertOOtoR);
std::vector<MyBean> beans = tm.selectAll<MyBean>(convertRtoOO);