在drogon框架之中,加入了ORM功能,使用在C++代码中嵌入很多的SQL语句,不仅让代码凌乱难看,更是需要很好的数据库语句编写功底,而使用ORM,则能够讲操作数据库转化为操作对象,在ORM中,通常一张表对应一个类,类的每个实例对应表中的一条记录,类的每个属性对应表中的每个字段。
ORM提供了对数据库的映射,不用直接编写SQL代码,只需操作对象就能对数据库操作数据。
让软件开发人员专注于业务逻辑的处理,提高了开发效率。
Model
使用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来访问、修改数据库,一是直接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条数据。