当前位置:   article > 正文

Delphi和C++ Builder中的Hibernate开发(二)

sexwrite

在Hibernate中有PO对象和POJO对象,

POJO = pure old java object or plain ordinary java object or what ever.

PO = persisent object 持久对象

就是说在一些Object/Relation Mapping工具中,能够做到维护数据库表记录的persisent object完全是一个符合Java Bean规范的纯Java对象,没有增加别的属性和方法。

持久对象实际上必须对应数据库中的entity,以如下数据库QQGroup为例,其中有5张表,Member为成员表,一个成员具有成果Researchs,也可能受到警告Warnings。

  1. CREATE DATABASE [QQGroup]
  2. GO
  3. USE [QQGroup]
  4. GO
  5. CREATE TABLE [Constants] (
  6. [Code] [varchar] (20) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  7. [Name] [varchar] (20) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  8. PRIMARY KEY CLUSTERED
  9. (
  10. [Code]
  11. ) ON [PRIMARY]
  12. ) ON [PRIMARY]
  13. GO
  14. CREATE TABLE [Idg] (
  15. [CODE] [varchar] (20) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  16. [NAME] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
  17. PRIMARY KEY CLUSTERED
  18. (
  19. [CODE]
  20. ) ON [PRIMARY]
  21. ) ON [PRIMARY]
  22. GO
  23. CREATE TABLE [Members] (
  24. [QQCode] [varchar] (20) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  25. [UserName] [varchar] (32) COLLATE Chinese_PRC_CI_AS NULL ,
  26. [Sex] [char] (1) COLLATE Chinese_PRC_CI_AS NULL ,
  27. [Age] [varchar] (10) COLLATE Chinese_PRC_CI_AS NULL ,
  28. [Area] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
  29. [NameCard] [varchar] (32) COLLATE Chinese_PRC_CI_AS NULL ,
  30. [Email] [varchar] (200) COLLATE Chinese_PRC_CI_AS NULL ,
  31. [WebSite] [varchar] (200) COLLATE Chinese_PRC_CI_AS NULL ,
  32. [Research] [ntext] COLLATE Chinese_PRC_CI_AS NULL ,
  33. [Status] [varchar] (12) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  34. [OutReason] [ntext] COLLATE Chinese_PRC_CI_AS NULL ,
  35. [InTime] [datetime] NULL ,
  36. [OutTime] [datetime] NULL ,
  37. [Identity1] [varchar] (12) COLLATE Chinese_PRC_CI_AS NULL ,
  38. [GotWarn] [char] (1) COLLATE Chinese_PRC_CI_AS NULL ,
  39. [GotResearch] [char] (1) COLLATE Chinese_PRC_CI_AS NULL ,
  40. CONSTRAINT [PK__Members__76CBA758] PRIMARY KEY CLUSTERED
  41. (
  42. [QQCode]
  43. ) ON [PRIMARY]
  44. ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
  45. GO
  46. CREATE TABLE [Researchs] (
  47. [SelfId] [varchar] (18) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  48. [QQCode] [varchar] (20) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  49. [Time] [datetime] NULL ,
  50. [Context] [ntext] COLLATE Chinese_PRC_CI_AS NULL ,
  51. PRIMARY KEY CLUSTERED
  52. (
  53. [SelfId]
  54. ) ON [PRIMARY]
  55. ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
  56. GO
  57. CREATE TABLE [Warnings] (
  58. [SelfId] [varchar] (18) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  59. [QQCode] [varchar] (20) COLLATE Chinese_PRC_CI_AS NOT NULL ,
  60. [WarnTime] [datetime] NOT NULL ,
  61. [Reason] [ntext] COLLATE Chinese_PRC_CI_AS NULL ,
  62. PRIMARY KEY CLUSTERED
  63. (
  64. [SelfId]
  65. ) ON [PRIMARY]
  66. ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
  67. GO
  68. INSERT INTO [Constants] VALUES('M', '男')
  69. INSERT INTO [Constants] VALUES('F', '女')
  70. INSERT INTO [Constants] VALUES('In', '在群')
  71. INSERT INTO [Constants] VALUES('Out', '已退群')
  72. INSERT INTO [Constants] VALUES('Admin', '管理员')
  73. INSERT INTO [Constants] VALUES('Member', '会员')
  74. INSERT INTO [Constants] VALUES('Y', '是')
  75. INSERT INTO [Constants] VALUES('N', '否')

 

在Delphi或C++ Builder中,我们可以定义表Members对应的持久对象TMembers为:

  1. (* This unit is created by My PODO generator *)
  2. unit PODO_MEMBERS;
  3. {$M+}
  4. interface
  5. uses
  6. Classes, SysUtils, UnitBaseTable;
  7. type
  8. TMembers = class(TTableData)
  9. private
  10. FQQCode: String;
  11. FUserName: String;
  12. FSex: String;
  13. FAge: String;
  14. FArea: String;
  15. FNameCard: String;
  16. FEmail: String;
  17. FWebSite: String;
  18. FResearch: Variant;
  19. FStatus: String;
  20. FOutReason: Variant;
  21. FInTime: TDateTime;
  22. FOutTime: TDateTime;
  23. FIdentity1: String;
  24. FGotResearch: String;
  25. FGotWarn: String;
  26. published
  27. property QQCode: String read FQQCode write FQQCode;
  28. property UserName: String read FUserName write FUserName;
  29. property Sex: String read FSex write FSex;
  30. property Age: String read FAge write FAge;
  31. property Area: String read FArea write FArea;
  32. property NameCard: String read FNameCard write FNameCard;
  33. property Email: String read FEmail write FEmail;
  34. property WebSite: String read FWebSite write FWebSite;
  35. property Research: Variant read FResearch write FResearch;
  36. property Status: String read FStatus write FStatus;
  37. property OutReason: Variant read FOutReason write FOutReason;
  38. property InTime: TDateTime read FInTime write FInTime;
  39. property OutTime: TDateTime read FOutTime write FOutTime;
  40. property Identity1: String read FIdentity write FIdentity;
  41. property GotWarn: String read FGotWarn write FGotWarn;
  42. property GotResearch: String read FGotResearch write FGotResearch;
  43. public
  44.   class
  45. function KeyColumnName: string;
  46. override;
  47.   class
  48. function TableName: string;
  49. override;
  50. end;
  51. implementation
  52. { TMembers }
  53. class function TMembers.KeyColumnName: string;
  54. begin
  55. result := 'QQCode';
  56. end;
  57. class function TMembers.TableName: string;
  58. begin
  59. result := 'Members';
  60. end;
  61. initialization
  62. RegisterClass(TMembers);
  63. end.

  从代码中可以看到TMembers类的定义的属性与表Members中的字段一一对应。

  所有的持久类继承自TTableData, TTableData的定义很关键,它是所有持久类的基类。如要新加一个子类,只需从TTableData类继承,然后在Published里申明相应的属性,属性名称与字段需要相同。同时为了对象内存管理方便,TTableData类从TPersistent继承,可以减少内存泄漏的可能性。VCL 的基类 TObject 本身不支持 RTTI(运行时类型信息),TPersistent 类通过 { $M+ } 编译指令提供了 RTTI(运行时类型信息) 的功能,打开了 M 开关后,Delphi 在编译该对象时,会把对象的类型信息也编译进可执行文件,这样在运行时就可以动态的获得对象的属性,方法等信息,所有的 VCL 可视化组件都是从 TPersistent 派生出来的,因此可以将组件信息保存成 DFM 文件,可以在运行时加载。

    那么如何实现一般对象的持久化(Persistent)呢, 解决方案如下:

  1. unit UnitBaseTable;
  2. // {$I MyUtils.inc}
  3. interface
  4. uses
  5. SysUtils, Windows, Messages, Classes, Contnrs, TypInfo,
  6. DB, Variants,
  7. MyUtils;
  8. type
  9. TTableData = class;
  10. TTableDataClass = class of TTableData;
  11. TTableClassArray = array of TTableDataClass;
  12. TTableData = class(TPersistent)
  13. private
  14. FFieldList: TStrings;
  15. FIsNew: Boolean;
  16. FModified: Boolean;
  17. FUniqueID: string;
  18. FDeleteFlag: Boolean;
  19. FGenerator: String;
  20. function GetFieldType(AName: string): Pointer;
  21. function GetValues(Name: string): Variant;
  22. procedure LoadFieldList;
  23. procedure SetValues(Name: string; Value: Variant);
  24. class function GetKeyValueWhere: string;
  25. protected
  26. procedure UpdateData; virtual;
  27. public
  28. constructor Create(); reintroduce; overload;
  29. constructor Create(AData: TDataSet); reintroduce; overload;
  30. constructor CreateNew(); virtual;
  31. destructor Destroy; override;
  32. // 判断字段类型
  33. function FieldIsBoolean(AName: string): Boolean;
  34. function FieldIsDateTime(AName: string): Boolean;
  35. function FieldIsFloat(AName: string): Boolean;
  36. function FieldIsInteger(AName: string): Boolean;
  37. function FieldIsString(AName: string): Boolean;
  38. // 字段是否存在
  39. function FieldExists(AName: string): Boolean;
  40. // 主键字段值
  41. function KeyValue: Variant;
  42. procedure UpdateValues(ASource: TDataSet);
  43. class function AutoKeyValue: Boolean; virtual;
  44. class function KeyColumnName: string; virtual;
  45. class function TableName: string; virtual;
  46. class function GeneratorType: string; virtual;
  47. // 是否使用主键PrimaryKey
  48. class function UseUniqueID: Boolean; virtual;
  49. class function OrderByList: string; virtual;
  50. class function PropertyExists(AName: string): Boolean;
  51. property FieldList: TStrings read FFieldList;
  52. property IsNew: Boolean read FIsNew write FIsNew;
  53. property Modified: Boolean read FModified write FModified;
  54. property Values[Name: string]: Variant read GetValues write SetValues;
  55. property DeleteFlag: Boolean read FDeleteFlag write FDeleteFlag;
  56. property UniqueID: string read FUniqueID write FUniqueID;
  57. property Generator: string read FGenerator write FGenerator;
  58. published
  59. //
  60. end;
  61. const
  62. COL_UNIQUEID = 'UniqueID';
  63. implementation
  64. uses
  65. unitDataOperator;
  66. { TBaseTable }
  67. {
  68. ********************************** TTableData **********************************
  69. }
  70. constructor TTableData.Create();
  71. begin
  72. inherited Create();
  73. FFieldList := TStringList.Create;
  74. LoadFieldList;
  75. end;
  76. constructor TTableData.Create(AData: TDataSet);
  77. begin
  78. UpdateValues(AData);
  79. UpdateData;
  80. end;
  81. constructor TTableData.CreateNew();
  82. begin
  83. FIsNew := True;
  84. // {$ifdef USE_UNIQUEID}
  85. // if UseUniqueID then
  86. // FUniqueID := GetNewGUID; //added by sunweijun
  87. // {$endif} // USE_UNIQUEID
  88. end;
  89. destructor TTableData.Destroy;
  90. begin
  91. FFieldList.Free;
  92. inherited Destroy;
  93. end;
  94. class function TTableData.AutoKeyValue: Boolean;
  95. begin
  96. // {$ifdef Use_UniqueID}
  97. Result := False;
  98. if UseUniqueID then
  99. Result := (GeneratorType = 'increment') or (GeneratorType = 'native') or
  100. (GeneratorType = 'identity');
  101. // {$endif} // Use_UniqueID
  102. end;
  103. function TTableData.FieldIsBoolean(AName: string): Boolean;
  104. begin
  105. Result := GetFieldType(AName) = TypeInfo(Boolean);
  106. end;
  107. function TTableData.FieldIsDateTime(AName: string): Boolean;
  108. begin
  109. Result := GetFieldType(AName) = TypeInfo(TDateTime);
  110. end;
  111. function TTableData.FieldIsFloat(AName: string): Boolean;
  112. begin
  113. Result := GetFieldType(AName) = TypeInfo(Real);
  114. end;
  115. function TTableData.FieldIsInteger(AName: string): Boolean;
  116. begin
  117. Result := GetFieldType(AName) = TypeInfo(Integer);
  118. end;
  119. function TTableData.FieldIsString(AName: string): Boolean;
  120. begin
  121. Result := GetFieldType(AName) = TypeInfo(String);
  122. end;
  123. class function TTableData.GeneratorType: string;
  124. begin
  125. Result := 'assigned';
  126. end;
  127. function TTableData.GetFieldType(AName: string): Pointer;
  128. begin
  129. Result := PPropInfo(FFieldList.Objects[FFieldList.IndexOf(AName)])^.PropType^;
  130. end;
  131. function TTableData.GetValues(Name: string): Variant;
  132. begin
  133. Result := GetPropValue(Self, Name, False);
  134. end;
  135. class function TTableData.KeyColumnName: string;
  136. begin
  137. Result := EmptyStr;
  138. end;
  139. function TTableData.KeyValue: Variant;
  140. begin
  141. if KeyColumnName <> EmptyStr then
  142. Result := GetValues(KeyColumnName);
  143. end;
  144. procedure TTableData.LoadFieldList;
  145. var
  146. PropCount, I: SmallInt;
  147. PropList: PPropList;
  148. PropName: string;
  149. begin
  150. PropCount := GetTypeData(ClassInfo).PropCount;
  151. GetPropList(ClassInfo, PropList);
  152. try
  153. for I := 0 to PropCount - 1 do
  154. begin
  155. PropName := PropList[I]^.Name;
  156. FFieldList.AddObject(PropName, TObject(PropList[I]));
  157. end;
  158. finally
  159. // free resources
  160. FreeMem(PropList);
  161. end; // try/finally
  162. end;
  163. procedure TTableData.SetValues(Name: string; Value: Variant);
  164. begin
  165. if not VarIsNull(Value) then
  166. SetpropValue(Self, Name, Value);
  167. end;
  168. class function TTableData.TableName: string;
  169. begin
  170. Result := EmptyStr;
  171. end;
  172. procedure TTableData.UpdateData;
  173. begin
  174. end;
  175. procedure TTableData.UpdateValues(ASource: TDataSet);
  176. var
  177. I: Integer;
  178. fName: string;
  179. fValue: Variant;
  180. begin
  181. if ASource = nil then
  182. Exit;
  183. if not ASource.Active then
  184. ASource.Open;
  185. if ASource.Eof then
  186. raise Exception.CreateFmt('%s.UpdateValues: Not found data', [ClassName]);
  187. for I := 0 to ASource.FieldCount - 1 do // Iterate
  188. begin
  189. try
  190. fName := ASource.Fields[I].DisplayName;
  191. fValue := ASource.Fields[I].Value;
  192. if UseUniqueID and SameText(fName, COL_UNIQUEID) and VarIsNull(fValue)
  193. then
  194. // fValue := GetNewGUID; //added by sunweijun
  195. // {$endif} // Use_UniqueID
  196. if FFieldList.IndexOf(fName) > -1 then
  197. begin
  198. SetValues(fName, fValue);
  199. end;
  200. except
  201. on e: Exception do
  202. begin
  203. raise;
  204. end;
  205. end; // try/except
  206. end; // for
  207. end;
  208. class function TTableData.UseUniqueID: Boolean;
  209. begin
  210. Result := False;
  211. end;
  212. class function TTableData.OrderByList: string;
  213. begin
  214. Result := EmptyStr;
  215. end;
  216. class function TTableData.PropertyExists(AName: string): Boolean;
  217. var
  218. FPropInfo: PPropInfo;
  219. begin
  220. FPropInfo := GetpropInfo(ClassInfo, AName);
  221. Result := FPropInfo <> nil;
  222. // if result then
  223. // FreeMem(FPropInfo);
  224. end;
  225. function TTableData.FieldExists(AName: string): Boolean;
  226. begin
  227. Result := FieldList.IndexOf(AName) > -1;
  228. end;
  229. class function TTableData.GetKeyValueWhere: string;
  230. begin
  231. Result := KeyColumnName + ' = :' + KeyColumnName;
  232. end;
  233. end.

 

     本框架的设计不采用XML配置文件,因此在持久类的定义中要包含一些配置信息,类似于Java Hibernate里的注解功能。此处定义了两个类函数,KeyColumnName和TableName,分别返回关键字段名和表名。

  (1)返回表的关键列名:
  class function KeyColumnName: string; virtual;
  (2)返回表的名称:
  class function TableName: string; virtual;
  (3)表中的唯一字段是否使用GUID(默认不使用,如果不改的话可以不覆盖):
   class function UseUniqueID: Boolean; virtual;

       子类必须覆盖这些类函数。

 

转载于:https://www.cnblogs.com/gowithyou/archive/2012/02/25/delphiORM.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/234367
推荐阅读
相关标签
  

闽ICP备14008679号