初识kbmmw 中的ORM
在kbmmw 5.02.1 中,加入了ORM 的功能(这里可能和其他语言的定义不完全一样),我们就简单的认为
它就是一个类与数据库的转换吧。今天就先介绍一下如何通过kbmmw 的ORM 功能,实现类与数据库的相互
转换和操作。
前提条件:delphi 10.2.1
kbmmw 5.02.1
unidac 7.0.2
haosql for sql server 2008 非常不错的一个sql 管理器
启动haosql for sqlserver2008 管理器,启动数据库。

打开delphi ,建立一个标准的工程,放置如图的几个控件

设置uniconnection1 连接sql server 2008 数据库

ok
加入几个必要的单元,并设置好初始化代码。
unit mainp; interface uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
kbmMWORM, Vcl.StdCtrls, Data.DB, DBAccess, Uni, kbmMWCustomConnectionPool,
kbmMWCustomSQLMetaData, kbmMWMSSQLMetaData, kbmMWUniDAC, UniProvider,
SQLServerUniProvider, DASQLMonitor, UniSQLMonitor ; type
TForm2 = class(TForm)
kbmMWUNIDACConnectionPool1: TkbmMWUNIDACConnectionPool;
kbmMWMSSQLMetaData1: TkbmMWMSSQLMetaData;
UniConnection1: TUniConnection;
Button1: TButton;
SQLServerUniProvider1: TSQLServerUniProvider;
UniSQLMonitor1: TUniSQLMonitor;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
ORM:TkbmMWORM;
end; var
Form2: TForm2; implementation {$R *.dfm}
procedure TForm2.FormCreate(Sender: TObject);
begin
ORM:=TkbmMWORM.Create(kbmMWUNIDACConnectionPool1); // 建立ORM 对象
ORM.QueryMode:=mwoqmMixed;
end; procedure TForm2.FormDestroy(Sender: TObject);
begin
ORM.Free; // 释放ORM对象
end; end.
现在新建一个单元,定义一个联系人类,并加入对应的标注信息
unit uContact; interface
uses System.Generics.Collections,kbmMWNullable,kbmMWRTTI, kbmMWORM,DB; type [kbmMW_Table('name:CONTACT')] // 表名为 contact
TContact = class
private
FID:kbmMWNullable<string>;
FName:kbmMWNullable<string>;
FAddress:kbmMWNullable<string>;
FZipCode:kbmMWNullable<string>;
FCity:kbmMWNullable<string>;
FComments:kbmMWNullable<string>;
public
[kbmMW_Field('primary:true, generator:shortGuid',ftString,)] //主键,并自动生成为GUID
property ID:kbmMWNullable<string> read FID write FID;
[kbmMW_Field('name:NAME',ftString,)]
property Name:kbmMWNullable<string> read FName write FName;
[kbmMW_Field('name:ADDRESS',ftString,)]
property Address:kbmMWNullable<string> read FAddress write FAddress;
[kbmMW_Field('name:ZIPCODE',ftInteger)]
property ZipCode:kbmMWNullable<string> read FZipCode write FZipCode;
[kbmMW_Field('name:city',ftString,)]
property City:kbmMWNullable<string> read FCity write FCity;
[kbmMW_Field('name:comments',ftString,)]
property Comments:kbmMWNullable<string> read FComments write FComments;
end; implementation initialization
TkbmMWRTTI.EnableRTTI([TContact]); //开启RTTI
kbmMWRegisterKnownClasses([TContact]);//注册 对象 end.
好了,我们返回主窗体, 加入对应的代码,我们先建立对应的表。
procedure TForm2.Button1Click(Sender: TObject);
begin ORM.CreateTable([Tcontact]); end;
编译运行,点创建库 按钮,显示建表成功。

我们看看背后发生了什么?首先我们先在 sql monitor 里面,看看后台做了什么?

通过sql monitor, 我们可以非常清晰的看见,kbmmw 先在次数据库中查询是否有这个表,如果没有这个表,则根据Tcontact 中定义的
字段来生成对应的SQL 语句,执行这个SQL,在数据库中生成对应的表。

数据库中生产的完全没问题。我们下一步生成一些数据,看看是否正常。
生成数据代码
procedure TForm2.Button3Click(Sender: TObject);
var
t1,t2,t3:TContact ;
begin t1:=TContact.Create;
t1.Name:='红鱼儿';
t1.Address:='不告诉你';
t1.ZipCode:='';
t1.City:='四平';
t1.Comments:='老牌程序猿'; ORM.Persist(t1); t2:=TContact.Create;
t2.Name:='努力的干';
t2.Address:='还是不告诉你';
t2.ZipCode:='';
t2.City:='泸州';
t2.Comments:='变形金刚制造者'; ORM.Persist(t2); t3:=TContact.Create;
t3.Name:='清幽傲竹';
t3.Address:='就是不告诉你';
t3.ZipCode:='';
t3.City:='福州';
t3.Comments:='真的很帅的!'; ORM.Persist(t3); showmessage('操作成功'); end;


看看后台都有那些sql.实际上这个Persist 是更新和插入,如果更新失败就插入。
看看数据库里面的生成数据的效果。

完全正确。
下面看一下如何通过ORM 查询数据。
kbmmw orm 查询数据有三种方式。
// Query mode controls what syntax to use for queries.
// mwoqmMW (default) use kbmMW's SQL syntax and automatically
// rewrite the query to match supported databases.
// mwoqmNative provides the query string without alterations to the
// database.
// mwoqmMixed default use kbmMW's SQL syntax with automatic rewrite
// unless the first character in the query statement is #
TkbmMWORMQueryMode = (mwoqmMW,mwoqmNative,mwoqmMixed);
缺省使用kbmmw 自身的SQL 语法,并自动转换成对应的数据库语法
第二种是直接使用目标数据库的语法
第三种是混合方式, 如果查询首字母不是# 的话,就用kbmmw 自身的sql 语法。
我们使用混合模式查询
procedure TForm2.Button5Click(Sender: TObject);
var
o:TObjectList<Tcontact>;
begin
o:=TObjectList<Tcontact>(orm.Query(Tcontact,'#SELECT * FROM contact',true)); showmessage('共有'+o.Count.ToString +'条记录'); o.Free; end;
或者
procedure TForm2.Button5Click(Sender: TObject);
var
o:TObjectList<Tcontact>;
begin
o:=orm.QueryList<Tcontact>('#SELECT * FROM contact');
showmessage('共有'+o.Count.ToString +'条记录');
o.Free;
end;
运行结果

后台SQL 亦是如此

我们来查询单条数据,单挑数据有两种查询方式
一种是SQL 方式,一种ORM 方式
先介绍一下sql 方式
procedure TForm2.Button6Click(Sender: TObject);
var
o:Tcontact;
begin
o:=orm.Query<Tcontact>('#SELECT * FROM contact WHERE NAME=''红鱼儿'''); if o=nil then
begin
showmessage('没有查询到数据!');
exit;
end; showmessage(o.Comments); o.Free; end;
运行效果

使用kbmw ORM 方式查询
procedure TForm2.Button7Click(Sender: TObject);
var
o:Tcontact;
b:boolean;
begin
o:=orm.Query<Tcontact>(['name'],['红鱼儿'],mwoqoEQ);
if o=nil then
begin
showmessage('没有查询到数据!');
exit;
end;
showmessage(o.Comments);
o.Free; end;
运行结果

修改数据库
procedure TForm2.Button8Click(Sender: TObject);
var
o:Tcontact; begin
o:=orm.Query<Tcontact>(['name'],['红鱼儿'],mwoqoEQ);
if o=nil then
begin
showmessage('没有查询到数据!');
exit;
end; o.Name:='红鱼儿二代';
orm.Update(o); showmessage('修改成功!');
o.Free; end;
结果也一切正常
看看后台发生了什么?

数据库是否保存正确?

没问题,太爽了。
顺便添加一下删除的代码
procedure TForm2.Button9Click(Sender: TObject);
var
o:Tcontact; begin
o:=orm.Query<Tcontact>(['name'],['红鱼儿'],mwoqoEQ);
if o=nil then
begin
showmessage('没有查询到数据!');
exit;
end; orm.Delete(o); showmessage('删除成功!');
o.Free; end;
清除全部的数据
procedure TForm2.Button4Click(Sender: TObject);
begin
orm.PurgeTable(Tcontact); end;
删除建的表
procedure TForm2.Button2Click(Sender: TObject);
begin
ORM.DeleteTable([Tcontact])
end;
终于写完了。
大家对上面kbmmw 标注肯定很头疼,第一要记很多标注名,第二不能笔误,这个确实麻烦,
好消息是,作者已经把自动生产这些标注列入计划,期待后面的版本能直接自动生产,那就方便多了。
在没有自动声场之前,请大家参照一下说明,自己手工处理。
// ORM attribute syntax
// ====================
//
// kbmMW_Table - Define a table.
// Must be used on classes.
//
// Define a table named person.
// [kbmMW_Table('name:person')]
//
// Define 2 ascending indexes i_fieldname, and i_anotherfieldname on the field fieldname and anotherfieldname.
// [kbmMW_Table('name:person, index:fieldname, index:anotherfieldname...
//
// Define an ascending index named i1, on the field name
// [kbmMW_Table('name:person, index:{name:i1,field:name},...
//
// Define a descending index named i1, on the field name
// [kbmMW_Table('name:person, index:{name:i1,field:name,descending:true},...
//
// Define a compound unique index named i2, on the fields name and age. Name field part is descending.
// [kbmMW_Table('name:person, index:{name:i2,unique:true,fields:[{name:name,descending:true},{name:age}]
//
//
// kbmMW_Field - Define fields in a table.
// Must be used on properties within a class if they are to be persisted.
//
// Define a field that will be persisted. Its type will be decided for
// from the property type. String type fields will have a size of 50.
// Table field name will be the same as the property name.
// [kbmMW_Field]
//
// Define a field that will be persisted. It will accept unicode data of max 50 characters.
// It will have the same name as the property.
// [kbmMW_Field(ftWideString,50)]
//
// Define a field named id, and make it primary key. It will be automatically populated bu the generator shortGuid.
// [kbmMW_Field('name:id, primary:true, generator:shortGuid',ftString,40)]
// property ID:kbmMWNullable<string> read FID write FID;
//
// These generators exists:
// GUID - Returns a GUID formatted as a regular GUID {123e4567-e89b-12d3-a456-426655440000}
// SHORTGUID - Returns a short GUID where braces and dashes are missing: 123e4567e89b12d3a456426655440000
// SEQUENCE - Returns next unique number from a sequence. Provide name of sequencer in sequence property
// and optional sequencestart property (not supported by all databases!)
// DATETIME - Returns a date time value, formatted according to the dateFormat property.
//
// Define a field named id, and make it primary key. It will be populated by a sequence generator.
// Since no sequencer was given, one is automatically generated named s_tablename_fieldname
// [kbmMW_Field('name:id, primary:true, generator:sequence',ftInteger)]
// property ID:kbmMWNullable<integer> read FID write FID;
//
// Define a field named id, and make it primary key. It will be populated by sequence generator SEQ, starting from value 10.
// (not all databases supports sequencers with a defined start!)
// [kbmMW_Field('name:id, primary:true, generator:sequence, seqneuce:SEQ1, sequenceStart:10',ftInteger)]
// property ID:kbmMWNullable<integer> read FID write FID;
//
// Define a field named id, and make it primary key. It will be populated automatically by the database.
// (not all databases support auto increment type fields!)
// [kbmMW_Field('name:id, primary:true',ftAutoInc)]
// property ID:kbmMWNullable<integer> read FID write FID;
//
// Define a field named datetime containing date/time values as Delphi local time values.
// [kbmMW_Field('name:datetime',ftDateTime)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// Define a field named datetime containing date/time values as Delphi UTC values.
// [kbmMW_Field('name:datetime, dateFormat:UTC',ftDateTime)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// Define a field named datetime containing date/time values as Unix local time millisecs since EPOC.
// [kbmMW_Field('name:datetime, dateFormat:LOCALSINCEEPOCHMS',ftInt64)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// Define a field named datetime containing date/time values as Unix UTC time millisecs since EPOC.
// [kbmMW_Field('name:datetime, dateFormat:UTCSINCEEPOCHMS',ftInt64)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// Define a field named datetime containing date/time values as Unix local time secs since EPOC.
// [kbmMW_Field('name:datetime, dateFormat:LOCALSINCEEPOCH',ftInt64)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// Define a field named datetime containing date/time values as Unix UTC time secs since EPOC.
// [kbmMW_Field('name:datetime, dateFormat:UTCSINCEEPOCH',ftInt64)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// Define a field named datetime containing date/time values as ISO8601 formatted string.
// [kbmMW_Field('name:datetime, dateFormat:ISO8601',ftString,50)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// Define a field named datetime containing date/time values as RFC1123 formatted string.
// [kbmMW_Field('name:datetime, dateFormat:RFC1123',ftString,50)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// Define a field named datetime containing date/time values as NCSA formatted string.
// [kbmMW_Field('name:datetime, dateFormat:NCSA',ftString,50)]
// property DateTime:TkbmMWDateTime read FDateTime write FDateTime;
//
// kbmMW_Null - Specify NULL conversion.
// (This attribute is also used for object marshalling).
//
// If, for example, a property is of type integer, the property is not directly able to indicate a NULL state since
// all values of an integer are considered non NULL values.
// However its possible to define a specific value to be interpreted as NULL.
// Eg.
// [kbmMW_Field('name:somefield',ftInteger)]
// [kbmMW_Null(-1)]
// property MyProperty:integer read FMyProperty write FMyProperty;
//
// This will define that the value -1 must be interpreted as NULL when storing and retrieving data
// from the database.
//
// kbmMW_NotNull - Indicate that the property must never contain the NULL value (either interpreted via the kbmMW_Null attribute or actual).
// Eg.
// [kbmMW_Field('name:somefield',ftInteger)]
// [kbmMW_NotNull]
// property MyProperty:kbmMWNullable<integer> read FMyProperty write FMyProperty;
初识kbmmw 中的ORM的更多相关文章
- 初识kbmmw 中的smartbind功能
关于kbmmw smartbind 的开发原因及思路,大家可以参见官方的博客说明和红鱼儿的翻译. 今天我就实例操作一下,给大家演示一下具体实现. 我们新建一个工程 放几个基本的控件 在单元里面加上引用 ...
- KBMMW 中 IOS IPv6 的解决
自从今年苹果强制新上架的APP 必须支持Ipv6,很多原来需要网络支持的APP 就没法上架了. 别的我们就不说了,先说说kbmmw 中,如何解决这个问题. 要测试你的app 是否支持ipv6, 首先要 ...
- 珍惜每一滴水(kbmmw 中的内存调试)
作为一个服务器端的应用,最基本的要求就是稳定,当然要做一个稳定的服务器端,需要涉及到很多方面, 内存泄露就是稳定的一个致命杀手,因为服务器的物理内存是有限的,即使一个功能有很小的内存泄露,经过 长时间 ...
- 在指定时间干,必须干(kbmmw 中的事件调度)
从去年开始,kbmmw 慢慢增加内涵,除了完善各种服务外,陆续增加和扩展了作为一个中间件必须有的功能, 例如,权限管理.日志系统.调度系统.内存调试等功能. 今天给大家介绍一下kbmmw 的调度事件, ...
- 细数.NET 中那些ORM框架 —— 谈谈这些天的收获之一
细数.NET 中那些ORM框架 —— 谈谈这些天的收获之一(转) ADO.NET Entity Framework ADO.NET Entity Framework 是微软以 ADO.N ...
- SSH 框架学习之初识Java中的Action、Dao、Service、Model-收藏
SSH 框架学习之初识Java中的Action.Dao.Service.Model-----------------------------学到就要查,自己动手动脑!!! 基础知识目前不够,有感性 ...
- Node.js中的ORM
ORM2是一款基于Node.js实现的ORM框架,名字相当的霸气,算是同类框架中非常出色的一款,具体介绍请猛击:https://github.com/dresende/node-orm2 刚接触Nod ...
- Django中的ORM进阶操作
Django中的ORM进阶操作 Django中是通过ORM来操作数据库的,通过ORM可以很easy的实现与数据库的交互.但是仍然有几种操作是非常绕也特别容易混淆的.于是,针对这一块,来一个分类总结吧. ...
- 在Django中使用ORM创建图书管理系统
一.ORM(对象关系映射) 很多语言的web框架中都有这个概念 1. 为什么要有ORM? 1. 写程序离不开数据,要使用数据就需要连接数据库,但是不同的数据库在sql语句上(mysql,oracle等 ...
随机推荐
- UVM1
1.UVM: p_sequencer 的使用 http://blog.csdn.net/tingtang13/article/details/46546395
- 微信小程序开发——活动规则类文案文件读取及自动转换为小程序排版代码
前言: 最近做的小程序活动规则内容比较多,且一直处于修改中.由于小程序并不支持类似Html5中的预排版,所以,活动规则内容修改较大的时候,仍需要对新的内容用小程序的<text>组件做下排版 ...
- TZOJ 1321 Girls and Boys(匈牙利最大独立集)
描述 the second year of the university somebody started a study on the romantic relations between the ...
- FortiGate软件版本升级
1.Web界面升级 1)注意:升级前,务必做好配置备份 2)要点 1.FortiGate防火墙的每款型号都有单独的版本文件,升级前务必确认下当前的设备型号: 2.升级包的后缀名必须为.out,前缀任意 ...
- java中关于null的一些理解
1.null是Java中的关键字,像public.static.final.它是大小写敏感的,你不能将null写成Null或NULL,编译器将不能识别它们然后报错. 2.null是任何引用类型的默认值 ...
- gridview 显示数据库中的超链接
gridview默认情况下,数据库中存储的超链接,是不会显示的.它会直接把超链接字符显示出来. 例如:选定数据源后,gridview自动生成的列是这样的: <asp:BoundField Dat ...
- ubuntu下sudo apt-get update Sources 404 Not Found 解决方法
刚安装了ubuntu之后的主要安装命令无非就是apt-get install了,然而很多都在这里就夭折了. 使用apt-get install ***需要先执行apt-get update 加载文件包 ...
- js关于去重的写法
break和continue的区别和作用 break和continue都是用来控制循环结构的,主要是停止循环. 1.break 有时候我们想在某种条件出现的时候终止循环而不是等到循环条件为false才 ...
- avalon 如何隐藏首屏加载页面时出现的花括号
页面添加样式 .ms-controller{ visibility: hidden } 使用在ms-controller, ms-important的元素上加上这个ms-controller类名 &l ...
- [z]dbms_stats.lock_table_stats对于没有统计信息的表分区同样有效
常见的分区表DDL如 split partition.add partition都会生成没有统计信息的表分区table partition,长期以来我对dbms_stats.lock_table_st ...