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.

除非注明,本站文章均为原创或编译,转载请注明: 文章来自KENGINE | Kankanews.com

C++ ORM ODB 入门介绍(一)的更多相关文章

  1. C++ ORM ODB 入门介绍(二)

    目录[-] 1. ODB中的继承类型 2. abstract和polymorphic的区别 3.polymorphic表格 4.早期版本如何实现polymorphic 5.实例 本节主要介绍ODB中的 ...

  2. C++ ORM ODB 入门(三)

    本节介绍ODB的事务与 异常. 数据库操作经常涉及到操作多个表格,或者表格中的多行数据.因此必须保证整个过程是原子性的.ODB为数据库的事务提供了易于使用的接口. 使用odb::databse的相关方 ...

  3. C++ ORM ODB入门

    1.ORM ORM, Object Relational Mapping, 对象关系映射,用来将基于对象的数据结构映射到SQL的数据结构中.即将基于对象的数据映射到关系表中的字段,然后我们可以通过对象 ...

  4. C# BackgroundWorker组件学习入门介绍

    C# BackgroundWorker组件学习入门介绍 一个程序中需要进行大量的运算,并且需要在运算过程中支持用户一定的交互,为了获得更好的用户体验,使用BackgroundWorker来完成这一功能 ...

  5. 初识Hadoop入门介绍

    初识hadoop入门介绍 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用我们的项目,但是我会继续研究下去,技多不压身. < ...

  6. [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)

    最近在使用Python爬取网页内容时,总是遇到JS临时加载.动态获取网页信息的困难.例如爬取CSDN下载资源评论.搜狐图片中的“原图”等,此时尝试学习Phantomjs和CasperJS来解决这个问题 ...

  7. [Python爬虫] scrapy爬虫系列 <一>.安装及入门介绍

    前面介绍了很多Selenium基于自动测试的Python爬虫程序,主要利用它的xpath语句,通过分析网页DOM树结构进行爬取内容,同时可以结合Phantomjs模拟浏览器进行鼠标或键盘操作.但是,更 ...

  8. JavaScript入门介绍(二)

    JavaScript入门介绍 [函数] 函数function 是Javascript的基础模块单元,用于代码的复用.信息影藏和组合调用. function a(){} 函数对象Function Lit ...

  9. JavaScript入门介绍(一)

    JavaScript入门介绍 [经常使用的调试工具][w3school.com.cn在线编辑] [Chrome浏览器 开发调试工具]按F121.代码后台输出调试:console.log("t ...

随机推荐

  1. Markdown简单语法总结

    . 标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 2. 列表 无序列表 * 西瓜 * 葡萄 * 香蕉 - 西瓜 - 葡萄 - ...

  2. OSFM Tables

    OSFM - Oracle Shop Floor Management 1. (N) Shop Floor Manager > Lot Based Jobs (B: New) Status: U ...

  3. sql 日期时间格式转换

    Sql日期时间格式转换   sql server2000中使用convert来取得datetime数据类型样式(全) 日期数据格式的处理,两个示例: CONVERT(varchar(16), 时间一, ...

  4. c程序设计语言_习题1-11_学习单元测试,自己生成测试输入文件

    How would you test the word count program? What kinds of input are most likely to uncover bugs if th ...

  5. 期待已久的2012年度最佳jQuery插件揭晓

    近日,国外著名博客WDL发布了2012年度最佳 jQuery 插件.jQuery 自2006年发布以来,经过6年的迅速发展,目前已是最流行和使用最广泛的 JavaScript 框架,这主要归功于众多围 ...

  6. wpa_supplicant使用笔记

    还在搞8634,看不到头了..唉.wireless_tools的缺点是不支持WPA认证,所以有必要把wpa_supplicant也移植过来.无线 网卡是基于zydas芯片的,正好可以在网上搜到wpa_ ...

  7. linux tar 解压命令总结

    把常用的tar解压命令总结下,当作备忘: tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其 ...

  8. LightOJ 1245 Harmonic Number (II) 水题

    分析:一段区间的整数除法得到的结果肯定是相等的,然后找就行了,每次是循环一段区间,暴力 #include <cstdio> #include <iostream> #inclu ...

  9. 一个free的问题

    请看下面的代码: #include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sy ...

  10. android获取屏幕分辨率

    DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); dm. ...