C++ ORM ODB 入门介绍(一)
C++的语言特性决定了在C++中的ORM框架不可能像Java,C#那没有那么灵活。
C++的ORM框架一般都是基于模板,编译时,因此其效率比起Java中的ORM框架更高。
ODB是一个比较独立,成熟的基于C++Template的ORM框架。使用#pragma编译指令和ODB.exe编译器生成SQL的特化版本。#pragma指令,对于熟悉Java的ORM映射的oscer,可以认为和Java的注解类似。只不过Java的注解是运行时,而C++#pragma的指令是编译时。
ODB中的类的#pragma(注解)包含2种。
#pragma db value 和 #pragma db object
value所注解的类的对象,不可以成为一个独立的数据库对象。一般映射为数据库的1或者多列。如果有位value类兹自定义trait类,则可以映射为一列,否则默认情况下value类的每个字段映射一个列。当然value必须被某个object类所包含,并在object类所对应的表中线性化的展开列。
object所注解的类,会映射一个或者多个表格(当有集合成员时)。每个持久化的object对象代表数据库表格中的一行。默认情况下object类的每个原始数据成员(包含std::string)都会映射为数据库表格的一列,除非使用编译指令#pragma db transient 把字段声明为临时的,也就是该字段不保存与数据库中。
关于object的id,一般情况下数据库的每个对象都应该是唯一的,那么就需要有某个列或者多列来唯一标识,是的在整个表格中是唯一的。object类中只能指定一个字段作为对象的id,正常情况下是对应数据库的一列。如果想要指定多列组合为对象的id,需要使用value类对象作为object类的一个成员。不过是普通数据成员,还是value数据成员作为id,都需要使用#pragma db id来注解。数据库的id中(mysql,sqlite都有自动增长字段)的auto指令,可以让数据库自己管理id,在持久化的时候,自动分配给object对象一个id,但是要求id的数据类型必须是整形。ODB也支持没有id的object类,但是那样的话,就无法使用find或者load等方法加载持久对象了。只能通过查询语句加载对象。
关于集合:OBD支持vector、list、set、multiset等有序和无序的集合,还支持map、mulitimap
对于集合的嵌套目前只支持一层(如果是对象集合则不受此限制,此处是值集合)。除非使用trait把集合映射为一列,因为默认情况下集合映射为一个表格,并通过外键和自己所在的object类的表格关联起来。集合最好不要放在value类中,除非你能保证该value类不会被当做其它集合的成员,否则就出现了多层嵌套集合,这个目前ODB是无法处理的。
ODB对象间关系:一个object可以包含另外一个object(只能是指针),就形成了object与object之间的关系了。包含一对一单向,一对一双向,一对多单向,一对多双向,多对多双向等5种关系。
一对一单向最简单,支持RAW ptr,shared_ptr,weak_ptr等。建议使用shared_ptre或者weak_ptr,可以自动管理对象的生命周期。一对一单向可能是唯一所有权,也可能是共享所有权。例如有object A,B两个类,其中object A包含一个object B的对象。如果任何一个object B的对象只被一个object A对象所包含的话,那么最好使用shared_ptr,如果同时有可能多个object A包含 object B对象的话,最好使用weak_ptr。
对于双向对象,建议一边使用shared_ptr,一边使用weak_ptr,否则在释放对象的时候还需要手动解引。默认情况下数据库表格会保存双方的id,也就是tblA有一个colBid,tblB有一个colAid,但是一般情况下没有必须要,可以在一边使用#pragma db reverse(双向引用对方的字段名称),来告诉数据库,从对方表格获得次对象。
一对多或者多对多,也就是集合中的数据是object对象. ODB编译器会创建一个表格用于关联2个对象之间的关系。同样建议使用shared_ptr\weak_ptr组合。对于多对多无法使用#pramga db reverse,但是对于一对多,则建议在集合的一方使用#pragma db reverse
关于继承体系。一般情况下我们的业务数据都有一定的体系结构的。例如学校的老师和学生,都是从person类对象继承而来的。ODB2.0及其以后的版本对此支持已经比较完善,而且也支持动态加载。在1.5版本的时候,即使teacher和student都继承自person,都不能使用load(name)或者find(name)来加载一个person,必须知道次name究竟是teacher还是student。2.0版本就可以直接使用了,因为在数据库内部已经保存了某条对象的类类型。使用起来和普通的C++类继承完全一样。想要让某个object成为支持动态联编的基类,在#pragma db object 的时候,必须在附加上polymorphic指令,也就是 #pragma db object polymorphic,只有基类才需要这样哦。如果是派生类则和普通的object一样的编译指令即可。
关于dbevent:数据库有触发器。dbevent是OBD提供的基于框架级别的触发器。供有6种类型的触发器。
pre_persist : 对象持久化之前被调用,再次可以抛出某些异常阻止对象被持久化。例如检查某个字段是否合法,检查某些对象的指针是否必须不能为null等。
post_persist:对象持久化之后被调用,再次可以做某些通知,关联之类的操作。
pre_load:对象从数据库第一次或者重新加载时,抛出异常,阻止加载。
post_load: 对象已经从数据库加载完成。
pre_update : 更新对象的内存信息到数据库之前。抛出异常阻止加载,此时抛出异常,会导致内存的数据和数据库数据不匹配,可以通过load方法从数据库加载最新的内容。
post_update : 数据更新完成。
pre_erase : 从数据库删除之前。可以抛出异常,阻止删除。
post_erase: 已经从数据库删除。但是内存对象并没有删除,需要自己删除,此时不能在此对象上调用load,update,erase操作。否则ODB会抛出异常。如果涉及到对象关系,再次可以解引用。
实例:一下是本人某工程的一个简单实例:
#ifndef __DATA_MODEL_H__
#define __DATA_MODEL_H__ #include <memory>
#include <string>
#include <set>
#include <list>
#include <vector> // ODB相关头文件.
#include <odb/database.hxx>
#include <odb/tr1/memory.hxx>
#include <odb/callback.hxx> #include <ace/Thread_Mutex.h>
#include <ace/Time_Value.h> using namespace std::tr1; class Entity;
class Zone;
class Terminal;
class User; enum EntityType {
TERMINAL = 0,
USER = 1,
ZONE = 3
};
/*
object 告诉ODB编译器,Entity为一个持久类。
table 告诉 ODB编译器,Entity类对应的表名称为tblEntity,如果没有改指令则表名与类名相同
polymorphic 告诉编译器,Entity是一个虚拟基类,数据库中并不存在tblEntity的直接对象。有点类似与C++的虚拟基类(当在此处,Entity不能有任何未实行的虚拟成员)
callback 指定语言级别的触发器。需要包含一个const版本和一个非const版本,其它签名完全相同.
*/ #pragma db object table("tblEntity") polymorphic callback(dbevent)
class Entity : public enable_shared_from_this<Entity>
{
//使得odb.exe生成的trait代码可以直接读取字段成员,否则需要告诉odb编译器对某个字段的get.set方法分别是啥.
friend class odb::access;
public:
Entity();
Entity(const Entity & other);
Entity & operator=( const Entity &other);
public: virtual void dbevent( odb::callback_event e, odb::database& db );
virtual void dbevent( odb::callback_event e, odb::database& db ) const;
virtual EntityType GetType() const;
void SetType( EntityType t);
public:
//get set
unsigned int GetId() const; const std::string & GetName() const;
//std::string & GetName(); shared_ptr<Zone> GetParent() const ; void SetId(unsigned int value);
void SetName(const std::string & value);
void SetParent( const shared_ptr<Zone> & value) ; private:
//指定id和自动增长。
#pragma db id auto
unsigned int id_;
std::string name_;
shared_ptr<Zone> parent_;
//临时自动,不保存与数据库.
#pragma db transient
EntityType type_;
}; #pragma db object table("tblZone") callback(dbevent)
class Zone : public Entity
{
friend class odb::access;
public:
Zone();
Zone(const Zone & other);
Zone & operator=( const Zone & other); virtual EntityType GetType() const;
public:
void Add( const shared_ptr<Entity> & en);
void Remove( const shared_ptr<Entity> & en);
shared_ptr<Entity> Find( unsigned int id, bool recursive = true);
shared_ptr<Entity> Find( const std::string & name , bool recursive = true);
shared_ptr<Terminal> FindTerminalByNtid( const std::string & macAddress); public:
//get set
const std::set < shared_ptr < Entity > > & GetMembers() const;
/*
std::set < shared_ptr < Entity > > & GetMembers();
*/ /*for Zone CPlusPlusSet*/
void SetMembers( const std::set < shared_ptr < Entity > > &value) ;
private:
//与Entity类是一对多关系,使用inverse告诉odb编译器反向字段(必须,因为Entity可能包含多个Zone字段).
//ODB编译器不会为members_创建一个对象关联表格,在加载的时候通过SQL语句在tblEntity表格中查询members_。
#pragma db inverse(parent_)
std::set< shared_ptr<Entity> > members_;
#pragma db transient
mutable ACE_Thread_Mutex mutex_;
};
//设备端口类型..fxs ( 0 ) , ivr ( 1 ) , group ( 2 ) , fxo ( 3 ) , gsm ( 4 )
enum PortType
{
FXS = 0,
IVR = 1,
Group = 2,
FXO = 3 ,
GSM = 4 ,
UNKNOWN = 5
};
//呼叫协议
enum ProtocolType
{
SIP = 0,
MGCP = 1,
H248 = 2,
H323 = 3
};
// 设备操作系统类型
enum SystemType
{
Linux = 0,
Vxworks = 1
};
enum TerminalStatus
{
OffLine = 0,
OnLine = 1,
DropLine = 2
};
#pragma db object table("tblTerminal") callback(dbevent)
class Terminal : public Entity
{
friend class odb::access;
public:
Terminal();
Terminal( const Terminal & other);
Terminal & operator=( const Terminal & other); virtual EntityType GetType() const; void dbevent( odb::callback_event e, odb::database& db );
void dbevent( odb::callback_event e, odb::database& db ) const;
public:
//get set
const std::string & GetMacAddress() const;
//std::string & GetMacAddress(); bool GetStaticAddress() const; const std::string & GetIpAddress() const;
//std::string & GetIpAddress(); unsigned int GetSnmpPort() const;
bool GetDynamicPorts() const; const std::vector < PortType > & GetPorts() const;
std::vector < PortType > & GetPorts(); ProtocolType GetProtocol() const;
unsigned int GetTimeToLive() const;
TerminalStatus GetOnline() const;
bool GetNat() const;
const std::string & GetAgentAddress() const; void SetMacAddress(const std::string & value);
void SetStaticAddress( bool value);
void SetIpAddress(const std::string & value);
void SetSnmpPort(unsigned int value);
void SetDynamicPorts( bool value);
void SetPorts( const std::vector < PortType > &value) ;
void SetProtocol( ProtocolType value);
void SetTimeToLive(unsigned int value);
void SetOnline( TerminalStatus value);
void SetOnlineTime(const std::string & value);
void SetOfflineTime(const std::string & value);
void SetDroplineTime(const std::string & value);
void SetDeviceType(const std::string & value);
void SetSoftwareVersion(const std::string & value);
void SetHardwareVersion(const std::string & value);
void SetRunningDuration( const std::string & value);
void SetNat( bool value);
void SetAgentAddress(const std::string & value); unsigned int GetTotalPorts() const ;
void SetTotalPorts(unsigned int val) ; SystemType GetSystemType() const ;
void SetSystemType(SystemType val) ; void SetRecvKeepalive() const;
bool IsTimeout() const;
int GetTTLMinUnit() const; bool HasTimer() const;
void SetTimer( bool val); const std::string & GetOnlineTime() const;
std::string & GetOnlineTime(); const std::string & GetOfflineTime() const;
std::string & GetOfflineTime(); const std::string & GetDroplineTime() const;
std::string & GetDroplineTime(); const std::string & GetDeviceType() const;
std::string & GetDeviceType(); const std::string & GetSoftwareVersion() const;
std::string & GetSoftwareVersion(); const std::string & GetHardwareVersion() const;
std::string & GetHardwareVersion(); const std::string & GetRunningDuration() const;
private:
//使用MAC地址作为区分设备的唯一标识.
std::string mac_address_;
// true ip_address_ & port_字段的内容由用户提供,否则通过socket地址获取.
bool static_address_;
std::string ip_address_;
unsigned int snmp_port_; //设备端口集合.
// true 表示 ports_的内容通过SNMP Trap消息获得,否则为用户新建设备时提供。
bool dynamic_ports_;
//设备端口个数..4,8,16,32
unsigned int total_ports_;
std::vector< PortType > ports_;
SystemType system_type_; //VOIP呼叫协议
ProtocolType protocol_; // 保活时间,接收到2个注册包或者保活包之间的最大间隔时间。超过此时间,系统会把online_设置为false.
unsigned int time_to_live_ ;
//设备是否在线
#pragma db transient
TerminalStatus online_;
#pragma db transient
mutable int last_keepalive_;
#pragma db transient
mutable bool tiemr_id_;
#pragma db transient
std::string online_time_;
#pragma db transient
std::string offline_time_;
#pragma db transient
std::string dropline_time_;
#pragma db transient
std::string device_type_;
#pragma db transient
std::string software_version_ ;
#pragma db transient
std::string hardware_version_;
#pragma db transient
std::string running_duration_;
#pragma db transient
bool nat_;
#pragma db transient
std::string agent_address_; }; #pragma db object table("tblUser") callback(dbevent)
class User : public Entity
{
friend class odb::access;
public:
User();
User( const User & other);
User & operator=( const User & other); virtual EntityType GetType() const;
public:
//get set const std::string & GetPassword() const;
//std::string & GetPassword(); bool GetAdministrator() const; void SetPassword(const std::string & value);
void SetAdministrator( bool value); bool GetOnline() const ;
void SetOnline(bool val) ;
private:
// 登陆密码
std::string password_;
// 是否为管理员,true 管理员,false 操作员
bool administrator_;
#pragma db transient
bool online_; };
#endif
声明:OSCHINA 博客文章版权属于作者,受法律保护。未经作者同意不得转载。
No tags for this post.
C++ ORM ODB 入门介绍(一)的更多相关文章
- C++ ORM ODB 入门介绍(二)
目录[-] 1. ODB中的继承类型 2. abstract和polymorphic的区别 3.polymorphic表格 4.早期版本如何实现polymorphic 5.实例 本节主要介绍ODB中的 ...
- C++ ORM ODB 入门(三)
本节介绍ODB的事务与 异常. 数据库操作经常涉及到操作多个表格,或者表格中的多行数据.因此必须保证整个过程是原子性的.ODB为数据库的事务提供了易于使用的接口. 使用odb::databse的相关方 ...
- C++ ORM ODB入门
1.ORM ORM, Object Relational Mapping, 对象关系映射,用来将基于对象的数据结构映射到SQL的数据结构中.即将基于对象的数据映射到关系表中的字段,然后我们可以通过对象 ...
- C# BackgroundWorker组件学习入门介绍
C# BackgroundWorker组件学习入门介绍 一个程序中需要进行大量的运算,并且需要在运算过程中支持用户一定的交互,为了获得更好的用户体验,使用BackgroundWorker来完成这一功能 ...
- 初识Hadoop入门介绍
初识hadoop入门介绍 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用我们的项目,但是我会继续研究下去,技多不压身. < ...
- [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)
最近在使用Python爬取网页内容时,总是遇到JS临时加载.动态获取网页信息的困难.例如爬取CSDN下载资源评论.搜狐图片中的“原图”等,此时尝试学习Phantomjs和CasperJS来解决这个问题 ...
- [Python爬虫] scrapy爬虫系列 <一>.安装及入门介绍
前面介绍了很多Selenium基于自动测试的Python爬虫程序,主要利用它的xpath语句,通过分析网页DOM树结构进行爬取内容,同时可以结合Phantomjs模拟浏览器进行鼠标或键盘操作.但是,更 ...
- JavaScript入门介绍(二)
JavaScript入门介绍 [函数] 函数function 是Javascript的基础模块单元,用于代码的复用.信息影藏和组合调用. function a(){} 函数对象Function Lit ...
- JavaScript入门介绍(一)
JavaScript入门介绍 [经常使用的调试工具][w3school.com.cn在线编辑] [Chrome浏览器 开发调试工具]按F121.代码后台输出调试:console.log("t ...
随机推荐
- Android java.net.SocketException四大异常解决方案
java.net.SocketException如何才能更好的使用呢?这个就需要我们先要了解有关这个语言的相关问题.希望大家有所帮助.那么我们就来看看有关java.net.SocketExceptio ...
- tshark 使用说明
yum install -y wireshark 最近才发现,原来wireshark也提供有Linux命令行工具-tshark.tshark不仅有抓包的功能,还带了解析各种协议的能力.下面我们以两个实 ...
- 使用console进行性能测试和计算代码运行时间
对于前端开发人员,在开发过程中经常需要监控某些表达式或变量的值,如果使用用debugger会显得过于笨重,最常用的方法是会将值输出到控制台上方便调试.最常用的语句就是console.log(expre ...
- 看懂SqlServer查询计划
看懂SqlServer查询计划 阅读目录 开始 SQL Server 查找记录的方法 SQL Server Join 方式 更具体执行过程 索引统计信息:查询计划的选择依据 优化视图查询 推荐阅读-M ...
- 基于WebForm+EasyUI的业务管理系统形成之旅 -- 构建Web界面(Ⅴ)
上篇<基于WebForm+EasyUI的业务管理系统形成之旅 -- 数据统计>,主要介绍系统数据统计所采用图形.报表工具. 本篇将如何构建Web界面以及新增.编辑.导出数据等功能. 一.在 ...
- maven安装步骤
第一步:配置maven环境 maven3 安装: 安装 Maven 之前要求先确定你的 JDK 已经安装配置完成.Maven是 Apache 下的一个项目,目前最新版本是 3.0.4,我用的也是这个. ...
- nyoj 找球号三(除了一个数个数为基数,其他为偶数,编程之美上的)
#include<iostream> #include<stdio.h> using namespace std; int main() { int len; while(ci ...
- puppet yum仓库
http://tmz.fedorapeople.org/repo/puppet/epel/5/x86_64/ [epel-puppet] name=epel puppet baseurl=http:/ ...
- 问题-"Record not found or changed by another user"
回答1:===============================================================问题:clientdataset“Record not found ...
- hdoj 2553 N皇后问题【回溯+打表】
N皇后问题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...