用于C++的对象关系映射库—YB.ORM

news2024/11/24 0:18:11

1 介绍YB.ORM

在这里插入图片描述
YB.ORM 旨在简化与关系数据库交互的 C++ 应用程序的开发。

对象关系映射器(ORM) 通过将数据库表映射到类并将表行映射到应用程序中的对象来工作,这种方法可能不是对每个数据库应用程序都是最佳的,但它被证明在需要复杂逻辑和事务处理的应用程序中是合理的。

虽然这是一个正在进行的项目,但大多数功能都已经完成。

YB.ORM 项目的目标是:

  • 为 C++ 开发人员提供方
  • 便的 API
  • 保持C++的高性能
  • 保持源代码在不同平台和编译器之间轻松移植
  • 支持大多数主要的关系数据库管理系统(DBMS)

该工具使用了 Martin Fowler 在《企业应用程序架构模式》一书中解释的许多概念,即“延迟加载”、“身份映射”、“工作单元”等模式。同时,项目开发受到启发借助 Java 的Hibernate框架的强大功能,尤其是 Python 的SQLAlchemy设计。

对象关系映射

此部分可以参考我的另外一篇文章:https://blog.csdn.net/weixin_42887343/article/details/120664818

关系数据库现在非常普遍——从 Oracle 集群到嵌入式 SQLite 基于文件的数据库,关系数据库以具有列和行的矩形表的形式对数据进行操作。

从应用程序代码连接 SQL 数据库并不容易,看看普通的ODBC API 就知道了,针对数据库运行 SQL 语句的典型步骤可能包括以下内容:

  • 连接数据库,提供参数:主机、端口、模式、用户名、密码等。
  • 使用连接句柄,创建游标并准备SQL 语句,以文本形式提供 SQL 语句
  • 使用游标句柄,可选择将输出参数绑定到您的输出变量,这些变量将在提取完成时接收它们的值
  • 使用游标句柄,可选择将输入参数(位置参数或命名参数)绑定到您的输入变量
  • 可选地为输入变量分配它们的值
  • 使用游标,执行准备好的语句,可选择继续执行步骤 5
  • 可选择获取结果集的下一行,如果确定则查看您的输出变量,可选择重复第 7 步
  • 关闭游标
  • 关闭连接

YB.ORM库的使用

使用 ORM 从模型定义开始。它可能看起来像一个带有表和关系的 XML 文件,或者像一个类声明中的内联宏,或者一个处理访问者的模板函数。此步骤可能需要也可能不需要代码生成或某种其他类型的预处理。这些变体中的每一个都有其自身的优点和缺点。

让我们考虑一个具有两个实体的示例架构:Client和Order。它们之间是一对多的关系:一个Client可能有零个,也可能有多个Orders,每一个都Order属于一个Client。Clients存储在 table 中client_tbl,而它们的Orders 存储在 table 中order_tbl。

在 SQL 级别,该关系可以表示为子表中的列引用父表中的主键列的外键约束。从 ORM 的角度来看,这种关系通常由对象的属性来表示。类的实例具有对象引用属性,引用类的单个父对象。从关系的另一端看,一个类的实例可能有一个对象集合属性(也称为“ ”),可以用来遍历它的所有子对象。client_id order_tblid client_tblOrderClientClientbackrefOrder

让我们定义映射模式以及两个类Client和Order。

#include "orm/domain_object.h"
#include "orm/domain_factory.h"
#include "orm/schema_decl.h"
class Order;
class Client: public Yb::DomainObject {
YB_DECLARE(Client, "client_tbl", "client_seq", "client",
    YB_COL_PK(id, "id")
    YB_COL_DATA(dt, "dt", DATETIME)
    YB_COL_STR(name, "name", 100)
    YB_COL_STR(email, "email", 100)
    YB_COL_DATA(budget, "budget", DECIMAL)
    YB_REL_ONE(Client, owner, Order, orders, Yb::Relation::Restrict, "client_id", 1, 1)
    YB_COL_END)
public:
    int get_info() const { return 42; }
};
class Order: public Yb::DomainObject {
YB_DECLARE(Order, "order_tbl", "order_seq", "order",
    YB_COL_PK(id, "id")
    YB_COL_FK(client_id, "client_id", "client_tbl", "id")
    YB_COL(dt, "dt", DATETIME, 0, 0, Yb::Value("sysdate"), "", "", "", "")
    YB_COL_STR(memo, "memo", 100)
    YB_COL_DATA(total_sum, "total_sum", DECIMAL)
    YB_COL_DATA(paid_sum, "paid_sum", DECIMAL)
    YB_COL_DATA(paid_dt, "paid_dt", DATETIME)
    YB_REL_MANY(Client, owner, Order, orders, Yb::Relation::Restrict, "client_id", 1, 1)
    YB_COL_END)
public:
    const Yb::Decimal to_be_paid() {
        return total_sum - paid_sum.value(0);
    }
};

这些类声明可以放在标题或.cpp文件中。您的.cpp文件中还需要两句话才能使魔术生效:

YB_DEFINE(Client)
YB_DEFINE(Order)

类Client和Order会自动获得一些新的数据成员和方法。现在类的每个对象都有映射属性(id, dt, , …)。name这些属性可用于以读取和写入模式访问列数据,以及检查是否存在缺失值 ( IS NULL)。

要控制映射类的实例,必须有一个类的实例Yb::Session,它负责加载/保存对象、跟踪更改、控制关系等。在创建时,Session将数据库方案传递给它。

int main() {
    Yb::init_schema();  // gather all declarations in one schema
    Yb::Session session(Yb::theSchema(), "sqlite+sqlite://./tut1.db");
    session.create_schema(true);  // create schema if necessary

现在你可以像那样立即使用域类:

Order order;
    order.total_sum = Yb::Decimal("3.14");
    order.paid_sum = Yb::Decimal(0);
    order.save(session);
    Client client;
    client.name = "Some Name";
    client.email = "some@email";
    client.dt = Yb::now();
    client.save(session);
    order.owner = Client::Holder(client);
    session.commit();
    return 0;
}

您可以编译示例,链接库ybutil和yborm,然后它就可以运行了。如果你愿意,你可以打开日志记录来查看引擎盖下发生了什么:

#include "util/nlogger.h"
#include <iostream>
...
    Yb::LogAppender appender(std::cerr);
    Yb::init_schema();  // gather all declarations in one schema
    Yb::Session session(Yb::theSchema(), "sqlite+sqlite://./tut1.db");
    session.set_logger(Yb::ILogger::Ptr(new Yb::Logger(&appender)));

以下是特定于 SQLite 数据库引擎的日志消息:

14-10-27 14:19:38.489 21962/21962 DEBG sql: exec_direct: CREATE TABLE client_tbl ( 
        id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
        dt TIMESTAMP, 
        name VARCHAR(100), 
        email VARCHAR(100), 
        budget NUMERIC 
) 
14-10-27 14:19:38.818 21962/21962 DEBG sql: exec_direct: CREATE TABLE order_tbl ( 
        id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
        client_id INTEGER NOT NULL, 
        dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, 
        memo VARCHAR(100), 
        total_sum NUMERIC, 
        paid_sum NUMERIC, 
        paid_dt TIMESTAMP 
        , FOREIGN KEY (client_id) REFERENCES client_tbl(id) 
) 
14-10-27 14:19:38.842 21962/21962 DEBG orm: flush started 
14-10-27 14:19:38.843 21962/21962 DEBG sql: begin transaction 
14-10-27 14:19:38.843 21962/21962 DEBG sql: 
prepare: INSERT INTO client_tbl (dt, name, email, budget) VALUES (?, ?, ?, ?) 
14-10-27 14:19:38.843 21962/21962 DEBG sql: bind: (DateTime, String, String, Decimal) 
14-10-27 14:19:38.843 21962/21962 DEBG sql: exec prepared: p1="'2014-10-27 
14:19:38'" p2="'Some Name'" p3="'some@email'" p4="NULL" 
14-10-27 14:19:38.844 21962/21962 DEBG sql: 
prepare: SELECT SEQ LID FROM SQLITE_SEQUENCE WHERE NAME = 'client_tbl' 
14-10-27 14:19:38.844 21962/21962 DEBG sql: exec prepared: 
14-10-27 14:19:38.844 21962/21962 DEBG sql: fetch: LID='1' 
14-10-27 14:19:38.844 21962/21962 DEBG sql: fetch: no more rows 
14-10-27 14:19:38.845 21962/21962 DEBG sql: prepare: INSERT INTO order_tbl 
(client_id, dt, memo, total_sum, paid_sum, paid_dt) VALUES (?, ?, ?, ?, ?, ?) 
14-10-27 14:19:38.845 21962/21962 DEBG sql: bind: (LongInt, DateTime, String, Decimal, Decimal, DateTime) 
14-10-27 14:19:38.845 21962/21962 DEBG sql: exec prepared: p1="1" 
p2="'2014-10-27 14:19:38'" p3="NULL" p4="3.14" p5="0" p6="NULL" 
14-10-27 14:19:38.845 21962/21962 DEBG sql: 
prepare: SELECT SEQ LID FROM SQLITE_SEQUENCE WHERE NAME = 'order_tbl' 
14-10-27 14:19:38.846 21962/21962 DEBG sql: exec prepared: 
14-10-27 14:19:38.846 21962/21962 DEBG sql: fetch: LID='1' 
14-10-27 14:19:38.846 21962/21962 DEBG sql: fetch: no more rows 
14-10-27 14:19:38.846 21962/21962 DEBG orm: flush finished OK 
14-10-27 14:19:38.846 21962/21962 DEBG sql: commit

注意正确的插入顺序(第一个 - 父母,第二个 - 孩子)。这是通过对对象图进行拓扑排序来实现的。外键的值是自动分配的,主键的值也是如此。

如果我们从另一端操纵对象之间的链接,也可以达到同样的效果:

//order.owner = Client::Holder(client);
client.orders.insert(order);

域类对于构造查询特别有用。例如,我们需要一个针对特定客户订单的寻呼机,让我们从 30 到 39(含)之间获取商品:

#include <boost/foreach.hpp>
...
    Yb::DomainResultSet<Order> rs = Yb::query<Order>(session) 
        .filter_by(Order::c.client_id == 32738) 
        .order_by(Order::c.dt) 
        .range(30, 40).all(); 
    BOOST_FOREACH(Order order, rs) { 
        std::cout << order.id << ","; 
    }

在这里,我们可以看到在不同 SQL 方言中实现不同的功能。例如,对于 SQLite,将发出以下 SQL 代码:

SQL:
SELECT order_tbl.id, order_tbl.client_id, order_tbl.dt, order_tbl.memo, 
 order_tbl.total_sum, order_tbl.paid_sum, order_tbl.paid_dt 
FROM order_tbl WHERE (order_tbl.client_id = ?)
ORDER BY order_tbl.dt
LIMIT ? OFFSET ?

positional params: (32738, 10, 30)

有关更多示例、下载和任何进一步信息,请访问项目主页https://sourceforge.net/projects/yborm/。

原文链接:https://www.codeproject.com/Articles/834803/Quick-Introduction-to-YB-ORM-Object-Relational-Map

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/374166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不怕被AirTag跟踪?苹果Find My技术越来越普及

苹果的 AirTag 自推出以来&#xff0c;如何有效遏制用户用其进行非法跟踪&#xff0c;是摆在苹果面前的一大难题。一家为执法部门制造无线扫描设备的公司近日通过 KickStarter 平台&#xff0c;众筹了一款消费级产品&#xff0c;可帮助用户检测周围是否存在追踪的 AirTag 等设备…

Spring中的FactoryBean 和 BeanFactory、BeanPostProcessor 和BeanFactoryPostProcessor解析

文章目录FactoryBean 和 BeanFactory后置处理器BeanPostProcessor 和 BeanFactoryPostProcessorBeanPostProcessorBeanFactoryPostProcessorFactoryBean 和 BeanFactory BeanFactory接⼝是容器的顶级接⼝&#xff0c;定义了容器的⼀些基础⾏为&#xff0c;负责⽣产和管理Bean的…

python元编程详解

什么是元编程 软件开发中很重要的一条原则就是“不要重复自己的工作&#xff08;Don’t repeat youself&#xff09;”&#xff0c;也就是说当我们需要复制粘贴代码时候&#xff0c;通常都需要寻找一个更加优雅的解决方案&#xff0c;在python中&#xff0c;这类问题常常会归类…

C++015-C++函数

文章目录C015-C函数函数目标char[]和stringchar[]char*string字符常量与字符串常量字符串的输入题目描述 字符串输出题目描述在线练习&#xff1a;总结C015-C函数 在线练习&#xff1a; http://noi.openjudge.cn/ https://www.luogu.com.cn/ 函数 目标 函数是指一段可以直接被…

SVG实例详解系列(一)(svg概述、位图和矢量图区别(图解)、SVG应用实例)

SVG实例详解系列&#xff08;一&#xff09; (svg概述、位图和矢量图区别&#xff08;图解&#xff09;、SVG应用实例&#xff09; 目录 一、什么是SVG? &#xff08;1&#xff09;、位图和矢量图概念&#xff08;图解&#xff09; &#xff08;2&#xff09;、SVG的小例子…

Flutter入门进阶之旅 -开源Flutter项目

开源Flutter项目 该项目为纯flutter端项目&#xff0c;采用aar方式寄生在原生APP中&#xff0c;作为APP中的一个独立模块 在业务逻辑上做到与原生APP完全隔离&#xff0c;Flutter端开发者&#xff0c;可完全不用关注原生端的业务模块 两端开发彼此业务隔离&#xff0c;缩小了对…

数字IC手撕代码--小米科技(除法器设计)

前言&#xff1a; 本专栏旨在记录高频笔面试手撕代码题&#xff0c;以备数字前端秋招&#xff0c;本专栏所有文章提供原理分析、代码及波形&#xff0c;所有代码均经过本人验证。目录如下&#xff1a;1.数字IC手撕代码-分频器&#xff08;任意偶数分频&#xff09;2.数字IC手撕…

wondows10系统python2.7兼容安装python3.10

假设已安装好python2.7和pyhon3.10。 python命令只需要应用程序改名即可&#xff0c;需要修改的有python.exe和pythonw.exe pip命令麻烦点&#xff0c;需要用改名后的程序名 重新安装&#xff0c;命令如下&#xff1a; python3 -m pip install --upgrade pip --force-reinst…

说说 Pluma 插件管理框架

1. 概述 Pluma 是一个用 C 开发的可用于管理插件的开源架构&#xff0c;其官网地址为&#xff1a;http://pluma-framework.sourceforge.net/。该架构是个轻量级架构&#xff0c;非常易于理解。 Pluma 架构有以下基本概念&#xff1a; 1&#xff09;插件的外在行为体现为一个…

【C++的OpenCV】第七课-OpenCV图像常用操作(四):图像形态学-图像侵蚀和扩散的原理

让我们来深化前边学习的内容前言一、图像形态学是什么&#xff1f;二、侵蚀和扩张的原理2.1 图像的侵蚀2.1.1 概念2.1.2 原理解释2.2 图像的扩张2.2.1 概念2.2.2 原理解释相关链接&#xff1a;【C的OpenCV】第六课-OpenCV图像常用操作&#xff08;三&#xff09;&#xff1a;Op…

RK3568镜像的拆包和打包

文章目录 前言一、window上分包和打包分包打包二、Linux上分包和打包分包打包总结前言 本文记录在win10上利用瑞芯微提供的工具进行分包和打包,同样也有Linux教程 提示:以下是本篇文章正文内容,下面案例可供参考 一、window上分包和打包 分包 window下一般直接利用工具即…

【正点原子FPGA连载】 第十八章基于BRAM的PS和PL的数据交互 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十八章基于BRA…

在 Flutter 中使用 webview_flutter 4.0 | 基础用法与事件处理

大家好&#xff0c;我是 17。 Flutter WebView 一共写了四篇文章 在 Flutter 中使用 webview_flutter 4.0 | 基础用法与事件处理在 Flutter 中使用 webview_flutter 4.0 | js 交互Flutter WebView 性能优化&#xff0c;让 h5 像原生页面一样优秀&#xff0c;已入选 掘金一周 …

AI绘画进军三次元,有人用它打造赛博女友?(diffusion)

目录0 写在前面1 AI绘画技术飞跃2 效果展示3 环境配置3.1 下载基础模型3.2 更新.NET和模型3.3 下载绘画模型3.4 启动项目3.5 标签配置4 结语0 写在前面 机器学习强基计划聚焦深度和广度&#xff0c;加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的数学原理&a…

内存数据库-4-[redis]在ubuntu中离线安装

Ubuntu20.04(linux)离线安装redis 官网redis下载地址 下载安装包redis-6.0.9.tar.gz。 1 下载安装 (1)解压 sudo tar -xzvf redis-6.0.9.tar.gz -C /usr/local/ cd /usr/local/redis-6.0.9/(2)编译 sudo make(3)测试 sudo dpkg -i libtcl8.6_8.6.10dfsg-1_amd64.deb sudo d…

纯x86汇编实现的多线程操作系统实践 - 第七章 AP2的用户进程

AP2用户进程的代码为task2.asm。该用户进程将在界面上显示一个移动的弹球。一旦在界面上点击鼠标左键&#xff0c;弹球就会直接从鼠标点击处重新出现并继续移动。如何在界面上显示出一个持续移动的小球&#xff1f;计算小球将移动到的区域1->保留该区域中将被小球覆盖的点-&…

智慧物联网源码带手机端源码 物联网系统源码

在智慧工厂领域&#xff0c;智慧城市领域&#xff0c;都需要对设备进行监控。比如工厂需要对周围环境温度、湿度、气压、电压&#xff0c;灯的开关进行监控。这时候就需要物联网平台来进行管理。 推荐一个基于java开发的物联网平台&#xff0c;前端HTML带云组态、可接入视频监…

【华为OD机试模拟题】用 C++ 实现 - 网上商城优惠活动(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明网上商城优惠活动题目输入输出备注示例一输入输出说明输入说明输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才…

Android zygote进程启动流程

zygote启动过程中涉及到以下模块&#xff1a; app_processzygote USAPsocketFileDescriptor (FD) AndroidRuntimeAppRuntime &#xff08;定义于app_process模块&#xff0c;继承自AndroidRuntime。&#xff09; init进程启动zygote进程&#xff1a; #init.zygote32_64.rc s…

【华为OD机试模拟题】用 C++ 实现 - 统计匹配的二元组个数(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明统计匹配的二元组个数题目输入输出描述示例一输入输出说明示例二输入输出说明备注Code使用说明 参加华为od机试,一定要注意不要完全背诵代码&