在drogon框架之中,加入了ORM功能,使用在C++代码中嵌入很多的SQL语句,不仅让代码凌乱难看,更是需要很好的数据库语句编写功底,而使用ORM,则能够讲操作数据库转化为操作对象,在ORM中,通常一张表对应一个类,类的每个实例对应表中的一条记录,类的每个属性对应表中的每个字段。
ORM提供了对数据库的映射,不用直接编写SQL代码,只需操作对象就能对数据库操作数据。
让软件开发人员专注于业务逻辑的处理,提高了开发效率。
使用Drogon的ORM支持,首先要创建Model类,Drogon的命令行程序drogon_ctl
提供了生成Model类的功能,它从用户指定的数据库读取表信息,根据这些信息自动生成多个Model类的源文件。用户使用Model时include对应的头文件即可。
显而易见,每一个Model类,对应一个特定的数据库表,每个Model类的实例,对应表的一行记录。
tables配置项是它特有的,是一个字符串数组,每个字符串表示要转化成Model的表名,如果该项为空,则所有的表都会生成对应的Model类。
用drogon_ctl create project命令创建的工程目录下已经预先创建了models目录和对应的model.json文件,用户可以编辑配置文件后用drogon_ctl命令创建Model类
model类的创建命令如下:
drogon_ctl create model
最后一个参数是model存放的路径,该路径内必须有一个配置文件model.json,用以配置drogon_ctl到数据库的连接参数,一般是直接使用models目录下得model.json。它是JSON格式的文件,支持注释,例子如下:
{ //rdbms: server type, postgresql,mysql or sqlite3 "rdbms": "mysql", //filename: sqlite3 db file name //"filename":"", //host: server address,localhost by default; "host": "127.0.0.1", //port: server port, 5432 by default; "port": 3306, //dbname: Database name; "dbname": "REST", //schema: valid for postgreSQL, "public" by default; "schema": "public", //user: User name "user": "root", //password or passwd: Password "password": "********", //client_encoding: The character set used by drogon_ctl. it is empty string by default which //means use the default character set. //"client_encoding": "", //table: An array of tables to be modelized. if the array is empty, all revealed tables are modelized. "tables": ["api_image_test"], //convert: the value can be changed by a function call before it is stored into database or //after it is read from database "convert": { "enabled": false, "items":[{ "table": "user", "column": "password", "method": { //after_db_read: name of the method which is called after reading from database, signature: void([const] std::shared_ptr [&]) "after_db_read": "decrypt_password", //before_db_write: name of the method which is called before writing to database, signature: void([const] std::shared_ptr [&]) "before_db_write": "encrypt_password" }, "includes": [ "\"file_local_search_path.h\"","<file_in_global_search_path.h>" ] }] }, "relationships": { "enabled": false, "items": [{ "type": "has one", "original_table_name": "products", "original_table_alias": "product", "original_key": "id", "target_table_name": "skus", "target_table_alias": "SKU", "target_key": "product_id", "enable_reverse": true }, { "type": "has many", "original_table_name": "products", "original_table_alias": "product", "original_key": "id", "target_table_name": "reviews", "target_table_alias": "", "target_key": "product_id", "enable_reverse": true }, { "type": "many to many", "original_table_name": "products", "original_table_alias": "", "original_key": "id", "pivot_table": { "table_name": "carts_products", "original_key": "product_id", "target_key": "cart_id" }, "target_table_name": "carts", "target_table_alias": "", "target_key": "id", "enable_reverse": true } ] }, "restful_api_controllers": { "enabled": false, // resource_uri: The URI to access the resource, the default value // is '/*' in which the asterisk represents the table name. // If this option is set to a empty string, the URI is composed of the namespaces and the class name. "resource_uri": "/*", // class_name: "Restful*Ctrl" by default, the asterisk represents the table name. // This option can contain namespaces. "class_name": "Restful*Ctrl", // filters: an array of filter names. "filters": [], // db_client: the database client used by the controller. this option must be consistent with // the configuration of the application. "db_client": { //name: Name of the client,'default' by default "name": "default", //is_fast: "is_fast": false }, // directory: The directory where the controller source files are stored. "directory": "controllers", // generate_base_only: false by default. Set to true to avoid overwriting custom subclasses. "generate_base_only": false } }
参数中需要填写数据库相应的配置数据,包括数据库地址,密码,数据库名,表名,这里的数据库和表必须是已经在数据库中已经存在的,这里与Django的ORM不用,不会自动创建数据库,而是将已经创建好的数据库在modles目录下新建一个类。
使用如下指令:
drongo_ctl create model modles
执行后将在models文件夹下产生.cc和.h文件,为表对应的类创建文件
/** * * ApiImageTest.cc * DO NOT EDIT. This file is generated by drogon_ctl * */ #include "ApiImageTest.h" #include <drogon/utils/Utilities.h> #include <string> using namespace drogon; using namespace drogon_model::REST; const std::string ApiImageTest::Cols::_id = "id"; const std::string ApiImageTest::Cols::_device_name = "device_name"; const std::string ApiImageTest::Cols::_img_url = "img_url"; const std::string ApiImageTest::primaryKeyName = "id"; const bool ApiImageTest::hasPrimaryKey = true; const std::string ApiImageTest::tableName = "api_image_test"; const std::vector<typename ApiImageTest::MetaData> ApiImageTest::metaData_={ {"id","int32_t","int",4,1,1,1}, {"device_name","std::string","varchar(64)",64,0,0,1}, {"img_url","std::string","varchar(100)",100,0,0,0} }; const std::string &ApiImageTest::getColumnName(size_t index) noexcept(false) { assert(index < metaData_.size()); return metaData_[index].colName_; } ApiImageTest::ApiImageTest(const Row &r, const ssize_t indexOffset) noexcept { if(indexOffset < 0) { if(!r["id"].isNull()) { id_=std::make_shared<int32_t>(r["id"].as<int32_t>()); } if(!r["device_name"].isNull()) { deviceName_=std::make_shared<std::string>(r["device_name"].as<std::string>()); } if(!r["img_url"].isNull()) { imgUrl_=std::make_shared<std::string>(r["img_url"].as<std::string>()); } } else { size_t offset = (size_t)indexOffset; if(offset + 3 > r.size()) { LOG_FATAL << "Invalid SQL result for this model"; return; } size_t index; index = offset + 0; if(!r[index].isNull()) { id_=std::make_shared<int32_t>(r[index].as<int32_t>()); } index = offset + 1; if(!r[index].isNull()) { deviceName_=std::make_shared<std::string>(r[index].as<std::string>()); } index = offset + 2; if(!r[index].isNull()) { imgUrl_=std::make_shared<std::string>(r[index].as<std::string>()); } } } ApiImageTest::ApiImageTest(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false) { if(pMasqueradingVector.size() != 3) { LOG_ERROR << "Bad masquerading vector"; return; } if(!pMasqueradingVector[0].empty() && pJson.isMember(pMasqueradingVector[0])) { dirtyFlag_[0] = true; if(!pJson[pMasqueradingVector[0]].isNull()) { id_=std::make_shared<int32_t>((int32_t)pJson[pMasqueradingVector[0]].asInt64()); } } if(!pMasqueradingVector[1].empty() && pJson.isMember(pMasqueradingVector[1])) { dirtyFlag_[1] = true; if(!pJson[pMasqueradingVector[1]].isNull()) { deviceName_=std::make_shared<std::string>(pJson[pMasqueradingVector[1]].asString()); } } if(!pMasqueradingVector[2].empty() && pJson.isMember(pMasqueradingVector[2])) { dirtyFlag_[2] = true; if(!pJson[pMasqueradingVector[2]].isNull()) { imgUrl_=std::make_shared<std::string>(pJson[pMasqueradingVector[2]].asString()); } } } ApiImageTest::ApiImageTest(const Json::Value &pJson) noexcept(false) { if(pJson.isMember("id")) { dirtyFlag_[0]=true; if(!pJson["id"].isNull()) { id_=std::make_shared<int32_t>((int32_t)pJson["id"].asInt64()); } } if(pJson.isMember("device_name")) { dirtyFlag_[1]=true; if(!pJson["device_name"].isNull()) { deviceName_=std::make_shared<std::string>(pJson["device_name"].asString()); } } if(pJson.isMember("img_url")) { dirtyFlag_[2]=true; if(!pJson["img_url"].isNull()) { imgUrl_=std::make_shared<std::string>(pJson["img_url"].asString()); } } } void ApiImageTest::updateByMasqueradedJson(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false) { if(pMasqueradingVector.size() != 3) { LOG_ERROR << "Bad masquerading vector"; return; } if(!pMasqueradingVector[0].empty() && pJson.isMember(pMasqueradingVector[0])) { if(!pJson[pMasqueradingVector[0]].isNull()) { id_=std::make_shared<int32_t>((int32_t)pJson[pMasqueradingVector[0]].asInt64()); } } if(!pMasqueradingVector[1].empty() && pJson.isMember(pMasqueradingVector[1])) { dirtyFlag_[1] = true; if(!pJson[pMasqueradingVector[1]].isNull()) { deviceName_=std::make_shared<std::string>(pJson[pMasqueradingVector[1]].asString()); } } if(!pMasqueradingVector[2].empty() && pJson.isMember(pMasqueradingVector[2])) { dirtyFlag_[2] = true; if(!pJson[pMasqueradingVector[2]].isNull()) { imgUrl_=std::make_shared<std::string>(pJson[pMasqueradingVector[2]].asString()); } } } void ApiImageTest::updateByJson(const Json::Value &pJson) noexcept(false) { if(pJson.isMember("id")) { if(!pJson["id"].isNull()) { id_=std::make_shared<int32_t>((int32_t)pJson["id"].asInt64()); } } if(pJson.isMember("device_name")) { dirtyFlag_[1] = true; if(!pJson["device_name"].isNull()) { deviceName_=std::make_shared<std::string>(pJson["device_name"].asString()); } } if(pJson.isMember("img_url")) { dirtyFlag_[2] = true; if(!pJson["img_url"].isNull()) { imgUrl_=std::make_shared<std::string>(pJson["img_url"].asString()); } } } const int32_t &ApiImageTest::getValueOfId() const noexcept { const static int32_t defaultValue = int32_t(); if(id_) return *id_; return defaultValue; } const std::shared_ptr<int32_t> &ApiImageTest::getId() const noexcept { return id_; } void ApiImageTest::setId(const int32_t &pId) noexcept { id_ = std::make_shared<int32_t>(pId); dirtyFlag_[0] = true; } const typename ApiImageTest::PrimaryKeyType & ApiImageTest::getPrimaryKey() const { assert(id_); return *id_; } const std::string &ApiImageTest::getValueOfDeviceName() const noexcept { const static std::string defaultValue = std::string(); if(deviceName_) return *deviceName_; return defaultValue; } const std::shared_ptr<std::string> &ApiImageTest::getDeviceName() const noexcept { return deviceName_; } void ApiImageTest::setDeviceName(const std::string &pDeviceName) noexcept { deviceName_ = std::make_shared<std::string>(pDeviceName); dirtyFlag_[1] = true; } void ApiImageTest::setDeviceName(std::string &&pDeviceName) noexcept { deviceName_ = std::make_shared<std::string>(std::move(pDeviceName)); dirtyFlag_[1] = true; } const std::string &ApiImageTest::getValueOfImgUrl() const noexcept { const static std::string defaultValue = std::string(); if(imgUrl_) return *imgUrl_; return defaultValue; } const std::shared_ptr<std::string> &ApiImageTest::getImgUrl() const noexcept { return imgUrl_; } void ApiImageTest::setImgUrl(const std::string &pImgUrl) noexcept { imgUrl_ = std::make_shared<std::string>(pImgUrl); dirtyFlag_[2] = true; } void ApiImageTest::setImgUrl(std::string &&pImgUrl) noexcept { imgUrl_ = std::make_shared<std::string>(std::move(pImgUrl)); dirtyFlag_[2] = true; } void ApiImageTest::setImgUrlToNull() noexcept { imgUrl_.reset(); dirtyFlag_[2] = true; } void ApiImageTest::updateId(const uint64_t id) { id_ = std::make_shared<int32_t>(static_cast<int32_t>(id)); } const std::vector<std::string> &ApiImageTest::insertColumns() noexcept { static const std::vector<std::string> inCols={ "device_name", "img_url" }; return inCols; } void ApiImageTest::outputArgs(drogon::orm::internal::SqlBinder &binder) const { if(dirtyFlag_[1]) { if(getDeviceName()) { binder << getValueOfDeviceName(); } else { binder << nullptr; } } if(dirtyFlag_[2]) { if(getImgUrl()) { binder << getValueOfImgUrl(); } else { binder << nullptr; } } } const std::vector<std::string> ApiImageTest::updateColumns() const { std::vector<std::string> ret; if(dirtyFlag_[1]) { ret.push_back(getColumnName(1)); } if(dirtyFlag_[2]) { ret.push_back(getColumnName(2)); } return ret; } void ApiImageTest::updateArgs(drogon::orm::internal::SqlBinder &binder) const { if(dirtyFlag_[1]) { if(getDeviceName()) { binder << getValueOfDeviceName(); } else { binder << nullptr; } } if(dirtyFlag_[2]) { if(getImgUrl()) { binder << getValueOfImgUrl(); } else { binder << nullptr; } } } Json::Value ApiImageTest::toJson() const { Json::Value ret; if(getId()) { ret["id"]=getValueOfId(); } else { ret["id"]=Json::Value(); } if(getDeviceName()) { ret["device_name"]=getValueOfDeviceName(); } else { ret["device_name"]=Json::Value(); } if(getImgUrl()) { ret["img_url"]=getValueOfImgUrl(); } else { ret["img_url"]=Json::Value(); } return ret; } Json::Value ApiImageTest::toMasqueradedJson( const std::vector<std::string> &pMasqueradingVector) const { Json::Value ret; if(pMasqueradingVector.size() == 3) { if(!pMasqueradingVector[0].empty()) { if(getId()) { ret[pMasqueradingVector[0]]=getValueOfId(); } else { ret[pMasqueradingVector[0]]=Json::Value(); } } if(!pMasqueradingVector[1].empty()) { if(getDeviceName()) { ret[pMasqueradingVector[1]]=getValueOfDeviceName(); } else { ret[pMasqueradingVector[1]]=Json::Value(); } } if(!pMasqueradingVector[2].empty()) { if(getImgUrl()) { ret[pMasqueradingVector[2]]=getValueOfImgUrl(); } else { ret[pMasqueradingVector[2]]=Json::Value(); } } return ret; } LOG_ERROR << "Masquerade failed"; if(getId()) { ret["id"]=getValueOfId(); } else { ret["id"]=Json::Value(); } if(getDeviceName()) { ret["device_name"]=getValueOfDeviceName(); } else { ret["device_name"]=Json::Value(); } if(getImgUrl()) { ret["img_url"]=getValueOfImgUrl(); } else { ret["img_url"]=Json::Value(); } return ret; } bool ApiImageTest::validateJsonForCreation(const Json::Value &pJson, std::string &err) { if(pJson.isMember("id")) { if(!validJsonOfField(0, "id", pJson["id"], err, true)) return false; } if(pJson.isMember("device_name")) { if(!validJsonOfField(1, "device_name", pJson["device_name"], err, true)) return false; } else { err="The device_name column cannot be null"; return false; } if(pJson.isMember("img_url")) { if(!validJsonOfField(2, "img_url", pJson["img_url"], err, true)) return false; } return true; } bool ApiImageTest::validateMasqueradedJsonForCreation(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector, std::string &err) { if(pMasqueradingVector.size() != 3) { err = "Bad masquerading vector"; return false; } try { if(!pMasqueradingVector[0].empty()) { if(pJson.isMember(pMasqueradingVector[0])) { if(!validJsonOfField(0, pMasqueradingVector[0], pJson[pMasqueradingVector[0]], err, true)) return false; } } if(!pMasqueradingVector[1].empty()) { if(pJson.isMember(pMasqueradingVector[1])) { if(!validJsonOfField(1, pMasqueradingVector[1], pJson[pMasqueradingVector[1]], err, true)) return false; } else { err="The " + pMasqueradingVector[1] + " column cannot be null"; return false; } } if(!pMasqueradingVector[2].empty()) { if(pJson.isMember(pMasqueradingVector[2])) { if(!validJsonOfField(2, pMasqueradingVector[2], pJson[pMasqueradingVector[2]], err, true)) return false; } } } catch(const Json::LogicError &e) { err = e.what(); return false; } return true; } bool ApiImageTest::validateJsonForUpdate(const Json::Value &pJson, std::string &err) { if(pJson.isMember("id")) { if(!validJsonOfField(0, "id", pJson["id"], err, false)) return false; } else { err = "The value of primary key must be set in the json object for update"; return false; } if(pJson.isMember("device_name")) { if(!validJsonOfField(1, "device_name", pJson["device_name"], err, false)) return false; } if(pJson.isMember("img_url")) { if(!validJsonOfField(2, "img_url", pJson["img_url"], err, false)) return false; } return true; } bool ApiImageTest::validateMasqueradedJsonForUpdate(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector, std::string &err) { if(pMasqueradingVector.size() != 3) { err = "Bad masquerading vector"; return false; } try { if(!pMasqueradingVector[0].empty() && pJson.isMember(pMasqueradingVector[0])) { if(!validJsonOfField(0, pMasqueradingVector[0], pJson[pMasqueradingVector[0]], err, false)) return false; } else { err = "The value of primary key must be set in the json object for update"; return false; } if(!pMasqueradingVector[1].empty() && pJson.isMember(pMasqueradingVector[1])) { if(!validJsonOfField(1, pMasqueradingVector[1], pJson[pMasqueradingVector[1]], err, false)) return false; } if(!pMasqueradingVector[2].empty() && pJson.isMember(pMasqueradingVector[2])) { if(!validJsonOfField(2, pMasqueradingVector[2], pJson[pMasqueradingVector[2]], err, false)) return false; } } catch(const Json::LogicError &e) { err = e.what(); return false; } return true; } bool ApiImageTest::validJsonOfField(size_t index, const std::string &fieldName, const Json::Value &pJson, std::string &err, bool isForCreation) { switch(index) { case 0: if(pJson.isNull()) { err="The " + fieldName + " column cannot be null"; return false; } if(isForCreation) { err="The automatic primary key cannot be set"; return false; } if(!pJson.isInt()) { err="Type error in the "+fieldName+" field"; return false; } break; case 1: if(pJson.isNull()) { err="The " + fieldName + " column cannot be null"; return false; } if(!pJson.isString()) { err="Type error in the "+fieldName+" field"; return false; } // asString().length() creates a string object, is there any better way to validate the length? if(pJson.isString() && pJson.asString().length() > 64) { err="String length exceeds limit for the " + fieldName + " field (the maximum value is 64)"; return false; } break; case 2: if(pJson.isNull()) { return true; } if(!pJson.isString()) { err="Type error in the "+fieldName+" field"; return false; } // asString().length() creates a string object, is there any better way to validate the length? if(pJson.isString() && pJson.asString().length() > 100) { err="String length exceeds limit for the " + fieldName + " field (the maximum value is 100)"; return false; } break; default: err="Internal error in the server"; return false; break; } return true; }
/** * * ApiImageTest.h * DO NOT EDIT. This file is generated by drogon_ctl * */ #pragma once #include <drogon/orm/Result.h> #include <drogon/orm/Row.h> #include <drogon/orm/Field.h> #include <drogon/orm/SqlBinder.h> #include <drogon/orm/Mapper.h> #ifdef __cpp_impl_coroutine #include <drogon/orm/CoroMapper.h> #endif #include <trantor/utils/Date.h> #include <trantor/utils/Logger.h> #include <json/json.h> #include <string> #include <memory> #include <vector> #include <tuple> #include <stdint.h> #include <iostream> using namespace drogon::orm; namespace drogon { namespace orm { class DbClient; using DbClientPtr = std::shared_ptr<DbClient>; } } namespace drogon_model { namespace REST { class ApiImageTest { public: struct Cols { static const std::string _id; static const std::string _device_name; static const std::string _img_url; }; const static int primaryKeyNumber; const static std::string tableName; const static bool hasPrimaryKey; const static std::string primaryKeyName; using PrimaryKeyType = int32_t; const PrimaryKeyType &getPrimaryKey() const; /** * @brief constructor * @param r One row of records in the SQL query result. * @param indexOffset Set the offset to -1 to access all columns by column names, * otherwise access all columns by offsets. * @note If the SQL is not a style of 'select * from table_name ...' (select all * columns by an asterisk), please set the offset to -1. */ explicit ApiImageTest(const Row &r, const ssize_t indexOffset = 0) noexcept; /** * @brief constructor * @param pJson The json object to construct a new instance. */ explicit ApiImageTest(const Json::Value &pJson) noexcept(false); /** * @brief constructor * @param pJson The json object to construct a new instance. * @param pMasqueradingVector The aliases of table columns. */ ApiImageTest(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false); ApiImageTest() = default; void updateByJson(const Json::Value &pJson) noexcept(false); void updateByMasqueradedJson(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false); static bool validateJsonForCreation(const Json::Value &pJson, std::string &err); static bool validateMasqueradedJsonForCreation(const Json::Value &, const std::vector<std::string> &pMasqueradingVector, std::string &err); static bool validateJsonForUpdate(const Json::Value &pJson, std::string &err); static bool validateMasqueradedJsonForUpdate(const Json::Value &, const std::vector<std::string> &pMasqueradingVector, std::string &err); static bool validJsonOfField(size_t index, const std::string &fieldName, const Json::Value &pJson, std::string &err, bool isForCreation); /** For column id */ ///Get the value of the column id, returns the default value if the column is null const int32_t &getValueOfId() const noexcept; ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null const std::shared_ptr<int32_t> &getId() const noexcept; ///Set the value of the column id void setId(const int32_t &pId) noexcept; /** For column device_name */ ///Get the value of the column device_name, returns the default value if the column is null const std::string &getValueOfDeviceName() const noexcept; ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null const std::shared_ptr<std::string> &getDeviceName() const noexcept; ///Set the value of the column device_name void setDeviceName(const std::string &pDeviceName) noexcept; void setDeviceName(std::string &&pDeviceName) noexcept; /** For column img_url */ ///Get the value of the column img_url, returns the default value if the column is null const std::string &getValueOfImgUrl() const noexcept; ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null const std::shared_ptr<std::string> &getImgUrl() const noexcept; ///Set the value of the column img_url void setImgUrl(const std::string &pImgUrl) noexcept; void setImgUrl(std::string &&pImgUrl) noexcept; void setImgUrlToNull() noexcept; static size_t getColumnNumber() noexcept { return 3; } static const std::string &getColumnName(size_t index) noexcept(false); Json::Value toJson() const; Json::Value toMasqueradedJson(const std::vector<std::string> &pMasqueradingVector) const; /// Relationship interfaces private: friend Mapper<ApiImageTest>; #ifdef __cpp_impl_coroutine friend CoroMapper<ApiImageTest>; #endif static const std::vector<std::string> &insertColumns() noexcept; void outputArgs(drogon::orm::internal::SqlBinder &binder) const; const std::vector<std::string> updateColumns() const; void updateArgs(drogon::orm::internal::SqlBinder &binder) const; ///For mysql or sqlite3 void updateId(const uint64_t id); std::shared_ptr<int32_t> id_; std::shared_ptr<std::string> deviceName_; std::shared_ptr<std::string> imgUrl_; struct MetaData { const std::string colName_; const std::string colType_; const std::string colDatabaseType_; const ssize_t colLength_; const bool isAutoVal_; const bool isPrimaryKey_; const bool notNull_; }; static const std::vector<MetaData> metaData_; bool dirtyFlag_[3]={ false }; public: static const std::string &sqlForFindingByPrimaryKey() { static const std::string sql="select * from " + tableName + " where id = ?"; return sql; } static const std::string &sqlForDeletingByPrimaryKey() { static const std::string sql="delete from " + tableName + " where id = ?"; return sql; } std::string sqlForInserting(bool &needSelection) const { std::string sql="insert into " + tableName + " ("; size_t parametersCount = 0; needSelection = false; sql += "id,"; ++parametersCount; if(dirtyFlag_[1]) { sql += "device_name,"; ++parametersCount; } if(dirtyFlag_[2]) { sql += "img_url,"; ++parametersCount; } needSelection=true; if(parametersCount > 0) { sql[sql.length()-1]=')'; sql += " values ("; } else sql += ") values ("; sql +="default,"; if(dirtyFlag_[1]) { sql.append("?,"); } if(dirtyFlag_[2]) { sql.append("?,"); } if(parametersCount > 0) { sql.resize(sql.length() - 1); } sql.append(1, ')'); LOG_TRACE << sql; return sql; } }; } // namespace REST } // namespace drogon_model
接下来就可以在项目中使用各个创建的Model类了,即可以使用ApiImageTest类了,对应的表为api_image_test。
该表包含id、device_name和img_url三个字段,分别对应ApiImageTest类中的三个属性。
有两种方式来利用Model来访问、修改数据库,一是直接Model类的接口,二是使用Mapper类模板,但是很遗憾,我在使用Model类接口是一直没有获取到数据库的相关信息,我们致力使用Mapper类模板来进行展示。
//控制台中文异常 std::system("chcp 65001"); auto clientPtr = drogon::app().getDbClient(); //同步查询 Mapper<ApiImageTest> mp(clientPtr); std::vector<ApiImageTest> news_list = mp.orderBy(ApiImageTest::Cols::_id).limit(15).offset(0).findAll(); std::cout << news_list.size() << " rows!" << std::endl;
当然你需要在使用ApiImageTest类的地方导入头文件
#include "../models/ApiImageTest.h"
在项目中运行此段代码后会打印出api_image_test表数据的行数。
运行效果图如下,数据库中有有15条数据。