C++ ORM ODB入门

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 1.ORM ORM, Object Relational Mapping, 对象关系映射,用来将基于对象的数据结构映射到SQL的数据结构中。即将基于对象的数据映射到关系表中的字段,然后我们可以通过对象提供的接口来操作数据库,而无需写sql语句来操作数据库。

1.ORM



ORM, Object Relational Mapping, 对象关系映射,用来将基于对象的数据结构映射到SQL的数据结构中。即将基于对象的数据映射到关系表中的字段,然后我们可以通过对象提供的接口来操作数据库,而无需写sql语句来操作数据库。
一般一张关系表对应两个类,一个实体类和一个操作类。
ORM是一种框架,而不是一种实现。


2.C++ 的ORM的实现ODB

1)一个简单的例子
#include <odb/core.hxx>  //(1) 


#pragma db object//(2) 


class person
{
public:
 person (const std::string& first,
 const std::string& last,
 unsigned short age);
 const std::string& first () const;
 const std::string& last () const;
 unsigned short age () const;
 void age (unsigned short);
private:
 person(); //(3)
 
 friend class odb::access;//(4)
 
 #pragma db id auto//(5)
 unsigned long id_;//(5)
 std::string first_;
 std::string email_;
 std::string last_;
 unsigned short age_;
};


Note:
(1) headers to provide class like 'access'


(2) 告诉编译器这是一个persistent class,所以我们要将#pragma db object放在类的定义前。将一个类声明为persistent class并不意味着这个类的所有对象都会被存储到数据库中。


(3)这个构造函数在实例化一个persistent class时会用到。


(4)让默认的构造函数和其它类成员能够访问access类。


(5)每个persistent object通常都要有一个独一无二的id.如果persistent object没有定义id,那么数据库的操作就会受限。
#pragma db id auto 用来指定这个对象id,auto表明这个id的值是有数据库自动分配的。
这个id可以使这个类本身就具有的成员,也可以是自己添加仅作为id来标识不同的persistent对象。上面的例子中的id_就是仅仅用来区别persistent object.


上面的例子我们也可以写成:
#include <odb/core.hxx>  //(1) 


#pragma db object//(2) 
class person
{
public:
 person();
 person (const std::string& first,
 const std::string& last,
 unsigned short age);
 const std::string& first () const;
 const std::string& last () const;
 unsigned short age () const;
 void age (unsigned short);
private:
 #pragma db id auto//(5)
 unsigned long id_;//(5)
 std::string first_;
 std::string email_;
 std::string last_;
 unsigned short age_;
};
//用来指定persistent 的id
#pragma db object(person)
#pragma db member(person::email_) id


3.用ODB编译器生成代码

将上面的代码保存为person.hxx,然后使用如下的命令来编译:
odb -d mysql --generate-query person.hxx
-d 用来指定我们使用的数据库。odb支持很多不同的数据库,我们以mysql为例。


这个命令会让odb的编译器生成三个文件:person-odb.hxx, person-odb.ixx, person-odb.cxx.


--generate-query用来指定编译器生成数据库支持的代码。如果我们使用--generate-shema, 那么还将生成person-odb.sql文件。


ok, 现在我们已经有persistent class(person.cxx)和database support code(person-odb.hxx, person-odb.ixx, person-odb.cxx)了。


4.编译和运行

假如我们的main文件为diver.cxx, 我们应该先编译main文件和上面生成的cxx文件:
c++ -c driver.cxx
c++ -c person-odb.cxx -Iyou_dir_to_odb_headers
c++ -o driver driver.o person-odb.o -Lyou_dir_to_odb_lib


在运行数据库前,记得先启动mysql并在库中使用指定表格。
mysql --user=user_name --database=you_db\


5.一个更加实用的例子

// driver.cxx
//
#include <memory> // std::auto_ptr
#include <iostream>
#include <odb/database.hxx> //定义database类
#include <odb/transaction.hxx> //定义transaction类
#include <odb/mysql/database.hxx> //实现database类的接口,同样要include
#include "person.hxx"
#include "person-odb.hxx"
using namespace std;
using namespace odb::core;//relative namespace.下面直接使用odb::batabase和odb::transaction就可以了,不用写成odb::core::database和odb::core::transaction了。


int
main (int argc, char* argv[])
{
 try
 {
 auto_ptr<database> db (new odb::mysql::database (argc, argv));//(1)
 unsigned long john_id, jane_id, joe_id;
 // Create a few persistent person objects.
 //
 {
 person john ("John", "Doe", 33);
 person jane ("Jane", "Doe", 32);
 person joe ("Joe", "Dirt", 30);
 transaction t (db->begin ());//(1)
 // Make objects persistent and save their ids for later use.
 //
 john_id = db->persist (john);//(2)
 jane_id = db->persist (jane);//(2)
 joe_id = db->persist (joe);//(2)
 t.commit ();//(3)
 }
 }
 catch (const odb::exception& e)
 {
 cerr << e.what () << endl;
 return 1;
 }
}


Note:
(1) 首先,我们要先创建一个database对象和transaction对象。
odb的实现中,所有database的操作都必须在一个transaction内进行。transaction是我们操作数据库的工作量的一个原子单位。一个transaction内包含有很过个database操作。如果一次transaction成功,则这个transaction内的数据库操作都会成功。如果一次transaction失败,这个transaction内的所有操作都会失败。


(2)我们在new了很多person对象后,使用persist选择奖哪些对象存储到数据库。


(3)提交一次transaction。如果在commit之前程序崩溃,所有的将要进行保存的数据库都不会被存储。


编译程序,然后开启数据库,然后执行程序。查看SQL的记录,我们可看到如下记录:
INSERT INTO ‘person‘ (‘id‘,‘first‘,‘last‘,‘age‘) VALUES (?,?,?,?)
INSERT INTO ‘person‘ (‘id‘,‘first‘,‘last‘,‘age‘) VALUES (?,?,?,?)
INSERT INTO ‘person‘ (‘id‘,‘first‘,‘last‘,‘age‘) VALUES (?,?,?,?)


6.查询数据库

 typedef odb::query<person> query;
 typedef odb::result<person> result;
 // Say hello to those over 30.
 //
 {
 transaction t (db->begin ());
 result r (db->query<person> (query::age > 30));
 for (result::iterator i (r.begin ()); i != r.end (); ++i)
 {
 cout << "Hello, " << i->first () << "!" << endl;
 }
 t.commit ();
 }
 }
 

 7.更新数据库

 (1)//使用object id
 unsigned long john_id, jane_id, joe_id;
 // Create a few persistent person objects.
 //
 {
 ...
 // Save object ids for later use.
//
 john_id = john.id ();
 jane_id = jane.id ();
 joe_id = joe.id ();
 }
 // Joe Dirt just had a birthday, so update his age.
 //
 {
 transaction t (db->begin ());
 auto_ptr<person> joe (db->load<person> (joe_id));
 joe->age (joe->age () + 1);
 db->update (*joe);
 t.commit ();
 }


 (2)不使用object id
  // Joe Dirt just had a birthday, so update his age. An
 // alternative implementation without using the object id.
 //
 {
 transaction t (db->begin ());
 result r (db->query<person> (query::first == "Joe" &&
 query::last == "Dirt"));
 result::iterator i (r.begin ());
 if (i != r.end ())
 {
 auto_ptr<person> joe (i.load ());
 joe->age (joe->age () + 1);
 db->update (*joe);
 }
 t.commit ();
 }

8.删除persistent object

删除一个object要使用到object 的id 
 // John Doe is no longer in our database.
 //
 {
 transaction t (db->begin ());
 db->erase<person> (john_id);
 t.commit ();
 }


 当然,也可以不用object id 
  // John Doe is no longer in our database. An alternative
 // implementation without using the object id.
 //
 {
 transaction t (db->begin ());
 result r (db->query<person> (query::first == "John" &&
 query::last == "Doe"));
 result::iterator i (r.begin ());
 if (i != r.end ())
 {
 auto_ptr<person> john (i.load ());
 db->erase (*john);
 }
 t.commit ();
 }

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
3月前
|
存储 安全 编译器
c++入门
c++作为面向对象的语言与c的简单区别:c语言作为面向过程的语言还是跟c++有很大的区别的,比如说一个简单的五子棋的实现对于c语言面向过程的设计思路是首先分析解决这个问题的步骤:(1)开始游戏(2)黑子先走(3)绘制画面(4)判断输赢(5)轮到白子(6)绘制画面(7)判断输赢(8)返回步骤(2) (9)输出最后结果。但对于c++就不一样了,在下五子棋的例子中,用面向对象的方法来解决的话,首先将整个五子棋游戏分为三个对象:(1)黑白双方,这两方的行为是一样的。(2)棋盘系统,负责绘制画面。
43 0
|
7月前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
6月前
|
存储 分布式计算 编译器
C++入门基础2
本内容主要讲解C++中的引用、inline函数和nullptr。引用是变量的别名,与原变量共享内存,定义时需初始化且不可更改指向对象,适用于传参和返回值以提高效率;const引用可增强代码灵活性。Inline函数通过展开提高效率,但是否展开由编译器决定,不建议分离声明与定义。Nullptr用于指针赋空,取代C语言中的NULL。最后鼓励持续学习,精进技能,提升竞争力。
|
11月前
|
编译器 C++
C++入门12——详解多态1
C++入门12——详解多态1
121 2
C++入门12——详解多态1
|
11月前
|
C++
C++入门13——详解多态2
C++入门13——详解多态2
160 1
|
11月前
|
存储 C++ 容器
C++入门9——list的使用
C++入门9——list的使用
88 1
|
11月前
|
C语言 C++ 容器
C++入门7——string类的使用-1
C++入门7——string类的使用-1
78 0
|
11月前
|
程序员 C语言 C++
C++入门5——C/C++动态内存管理(new与delete)
C++入门5——C/C++动态内存管理(new与delete)
200 1
|
11月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
171 0
C++入门6——模板(泛型编程、函数模板、类模板)