[NewLife.XCode]反向工程(自动建表建库大杀器)

NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netstandard,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode。

整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含多年开发经验于其中,代表作有百亿级大数据实时计算项目。

开源地址:https://github.com/NewLifeX/X (求star, 656+)

 

回到目录

大杀器

反向工程是XCode的大杀器,区别于其它ORM的最强功能!

通俗理解:基于XCode开发的应用,无需数据库安装脚本,连接字符串指向哪一台哪一种数据库,系统就自动在上面建库建表!

正式定义:基于实体类的表结构信息,在连接字符串指定的目标数据库上自动执行建库建表、添删改字段、创建索引等操作,支持各种数据库!

应用系统首次启动完成的时候,也是自动建表建库并初始化完成的时候。

反向工程是XCode数万级分表的主要倚仗!

 

创建控制台项目,从Nuget引用NewLife.XCode

创建实体类,模型如下(可参考前面几章来生成实体类):

640?wx_fmt=png

 测试代码:

640?wx_fmt=png

 执行日志:640?wx_fmt=png

自始至终,我们没有编写SQL脚本,没有去数据库创建数据表。

代码写完就跑起来,测试通过就部署到正式库。

从日志来看,程序自动下载SQLite驱动,因为我们并没有指定实体类使用哪一种数据库,XCode自动给我们配置了SQLite。(上一章连接字符串部分有讲解)

 

加一行代码把数据库指向MySql:

640?wx_fmt=png

 执行日志:

640?wx_fmt=png

同样的首先下载MySql驱动,(当然也可以自己通过nuget引用)。

首次连接数据库时,库名指定School报错,因为根本就不存在这个库。

因此,XCode切换到系统库,开始创建数据库School,并创建数据表和索引。这里完全是MySql语法,不同于上面的SQLite建表语句。

 

感兴趣的同学,还可以试试Oracle和SqlServer等数据库。

 

回到目录

正向工程

正向工程就是从数据库读取表结构信息,生成模型信息。

我们来试试写几行代码读取上面创建的数据表:

640?wx_fmt=png

执行日志:

640?wx_fmt=png

从上面可以看到,读取dal.Tables得到了这个连接的所有表结构信息,输出为Xml时,跟前面用来创建实体类的模型文件极为相似。

其实这就是一个模型文件,只是为了生成实体类的模型文件多增加了几个属性而已。

新生命码神工具XCoder,(https://github.com/NewLifeX/XCoder),其中的数据建模工具,可以导出各种数据库的表结构信息,正是基于dal.Tables来实现。

 

正向工程由3个基本接口构成:

  • IDataTable。数据表接口,dal.Tables就是IDataTable集合,包括名称、描述等

  • IDataColumn。数据列接口,每张数据表有多个数据列,包括名称、类型、长度、描述等

  • IDataIndex。数据索引接口,每张数据表没有或者有多个索引,索引指定包括哪些字段 ,是否唯一

 

回到目录

反向工程

有了IDataTable,我们就可以主动控制数据表结构。

DAL.SetTables(IDataTable[] tables);

这是反向工程高级用法,实际日常工作中用不到,各个实体类加载时,将会逐个连接进行反向工程检查,正是调用该方法。

 

给上面的数据模型,增加一个字段Code和对应索引:

640?wx_fmt=png

跑起来:

640?wx_fmt=png

程序自动为我们添加了字段,以及创建了索引!

前面的几个SHOW,就是XCode的正向工程,取得数据库表结构,然后跟实体类结构对比,不相同时执行反向操作。

 

回到目录

反向工程设置

大家还记得上一章系统设置中提到的Migration吗?

XCode.config和连接字符串中都支持这个设置。

可用设置项如下:

  • Off 关闭,不执行反向工程

  • ReadOnly 只读不执行,异步执行反向工程检查,对比后生成变更DDL写入日志

  • On 打开,仅新建,默认设置。新建表、增加字段、创建索引等可以执行,禁止修改字段长度类型,禁止删除字段,以免造成数据丢失

  • Full 完全,修改删除。除了新建表、增加字段、创建索引外,还可以修改字段长度类型、删除字段等,极其危险,慎用

反向工程设计于2008年,10多年经验表明,默认On最合理,不仅满足开发需要,(随时加字段),还避免了字段改变而导致的数据丢失风险;

 

反向工程如此神奇的功能,你想到了什么高端用法吗?我们将在数万级分表分库章节等你!

 

回到目录

系列教程

NewLife.XCode教程系列[2019版]

  1. 增删改查入门。快速展现用法,代码配置连接字符串

  2. 数据模型文件。建立表格字段和索引,名字以及数据类型规范,推荐字段(时间,用户,IP)

  3. 实体类详解。数据类业务类,泛型基类,接口

  4. 功能设置。连接字符串,调试开关,SQL日志,慢日志,参数化,执行超时。代码与配置文件设置,连接字符串局部设置

  5. 反向工程。自动建立数据库数据表

  6. 数据初始化。InitData写入初始化数据

  7. 高级增删改。重载拦截,自增字段,Valid验证,实体模型(时间,用户,IP)

  8. 脏数据。如何产生,怎么利用

  9. 增量累加。高并发统计

  10. 事务处理。单表和多表,不同连接,多种写法

  11. 扩展属性。多表关联,Map映射

  12. 高级查询。复杂条件,分页,自定义扩展FieldItem,查总记录数,查汇总统计

  13. 数据层缓存。Sql缓存,更新机制

  14. 实体缓存。全表整理缓存,更新机制

  15. 对象缓存。字典缓存,适用用户等数据较多场景。

  16. 百亿级性能。字段精炼,索引完备,合理查询,充分利用缓存

  17. 实体工厂。元数据,通用处理程序

  18. 角色权限。Membership

  19. 导入导出。Xml,Json,二进制,网络或文件

  20. 分表分库。常见拆分逻辑

  21. 高级统计。聚合统计,分组统计

  22. 批量写入。批量插入,批量Upsert,异步保存

  23. 实体队列。写入级缓存,提升性能。

  24. 备份同步。备份数据,恢复数据,同步数据

  25. 数据服务。提供RPC接口服务,远程执行查询,例如SQLite网络版

  26. 大数据分析。ETL抽取,调度计算处理,结果持久化

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您又发现了一个问题,这个代码确实没有实现返回上一代的功能。在代码中添加一个变量 `generation` 来记录当前的代数,然后在回滚时将代数减1,就可以回到上一代。可以按照以下方式修改代码: ```c++ int generation = 0; // 添加一个变量来记录当前的代数 A.init(ROWS, COLS, life); while (true) { A.display(ROWS, COLS, life); string input; loop: cout << "Type 's' to save, 'l' to load, 'c' to change,'s' to stop, 'r' to rollback, or any other key to continue: "; cin >> input; if (input == "s") { string fileName; cout << "Enter file name: "; cin >> fileName; A.saveBoard(life, fileName, ROWS, COLS); } else if (input == "r") { if (generation == 0) { cout << "Cannot rollback anymore!" << endl; } else { generation--; for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { life[i][j] = oldlife[i][j]; } } A.display(ROWS, COLS, life); } } else if (input == "l") { string fileName; cout << "Enter file name: "; cin >> fileName; A.loadBoard(life, fileName, ROWS, COLS); } else if (input == "c") { int x, y; cin >> x >> y; if (x >= 0 && x < ROWS && y >= 0 && y < COLS) { life[x][y] = ~life[x][y]; A.display(ROWS, COLS, life); goto loop; } else { cout << "Invalid position!" << endl; } } else if (input == "s") { break; } A.run(ROWS, COLS, life, newLife); generation++; // 更新当前的代数 for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { oldlife[i][j] = life[i][j]; } } } ``` 这样,当用户输入"r"时,如果当前的代数为0,代码会输出一个提示信息;否则,代码会将代数减1,并将oldlife的值复制到life中,然后再显示出来,实现了返回上一代的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值