UniDAC使用教程(四):數據類型映射

下載UniDAC最新版本數據庫

Universal Data Access Components (UniDAC)是一款通用數據庫訪問組件,提供了多個數據庫的直接訪問,如針對Windows的Delphi, C++Builder, Lazarus (以及 Free Pascal) , Mac OS X, iOS, Android, Linux和64和32位的FreeBSD等等。咱們將長期的經驗集於這個小組件,提供統一的數據庫鏈接訪問(如oracle、微軟SQL等等)。這意味着您能夠在您的項目之間輕鬆地切換不一樣的數據庫,以及建立跨數據庫應用程序接口。oracle

概述

Data Type Mapping數據類型映射是一種靈活且易於定製的工具,它容許在DB類型和Delphi字段類型之間進行映射。app

在本文中,有幾個示例,能夠在處理全部支持的DBS時使用。爲了清楚地顯示數據類型映射設備的通用性,每一個示例將使用單獨的數據庫。ide

數據類型映射規則

在不支持數據類型映射的版本中,UniDAC自動設置DB數據類型和Delphi 字段類型之間的對應關係。在具備數據類型映射的版本中,能夠手動設置DB數據類型和Delphi 字段類型之間的對應關係。工具

下面是PostgreSQL數據庫下表中數字類型的示例:ui

1spa

2設計

3code

4blog

5

6

7

8

CREATE TABLE numeric_types

(

 id integer NOT NULL,

 value1 numeric(5,2),

 value2 numeric(10,4),

 value3 numeric(15,6),

 CONSTRAINT pk_numeric_types PRIMARY KEY (id)

)

應使用數據類型映射,以便:

Delphi中Scale=0的數字字段將映射到如下字段類型之一:TSmallintField、TIntegerField 或TlargeintField,具體取決於精度

爲了保存精度,Precision>=10且Scalе<= 4的數字字段將映射到TBCDField。

數值字段Scalе>= 5將映射到TFMTBCDField。

以上表格形式:

UniDAC

要指定Precision <= 4且Scale = 0的數值字段必須映射到ftSmallint,應設置如下規則:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

var

  DBType: Word;

  MinPrecision: Integer;

  MaxPrecision: Integer;

  MinScale: Integer;

  MaxScale: Integer;

  FieldType: TfieldType;

begin

  DBType       := pgNumeric;

  MinPrecision := 0;

  MaxPrecision := 4;

  MinScale     := 0;

  MaxScale     := 0;

  FieldType    := ftSmallint;

  PgConnection.DataTypeMap.AddDBTypeRule(DBType, MinPrecision, MaxPrecision, MinScale, MaxScale, FieldType);

end;

這是詳細規則設置的一個例子,它是爲了最大限度地可視化而設計的。一般,規則設置得要短得多,例如以下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// clear existing rules

PgConnection.DataTypeMap.Clear;

// rule for numeric(4,0)

PgConnection.DataTypeMap.AddDBTypeRule(pgNumeric, 0,      4, 0,     0, ftSmallint);

// rule for numeric(10,0)

PgConnection.DataTypeMap.AddDBTypeRule(pgNumeric, 5,     10, 0,     0, ftInteger);

// rule for numeric(15,0)

PgConnection.DataTypeMap.AddDBTypeRule(pgNumeric, 11, rlAny, 0,     0, ftLargeint);

// rule for numeric(5,2)

PgConnection.DataTypeMap.AddDBTypeRule(pgNumeric, 0,      9, 1, rlAny, ftFloat);

// rule for numeric(10,4)

PgConnection.DataTypeMap.AddDBTypeRule(pgNumeric, 10, rlAny, 1,     4, ftBCD);

// rule for numeric(15,6)

PgConnection.DataTypeMap.AddDBTypeRule(pgNumeric, 10, rlAny, 5, rlAny, ftFMTBcd);

規則秩序

在設置規則時,可能會出現這樣的狀況:爲數據庫中的一個類型設置了兩個或多個相互矛盾的規則。在這種狀況下,將只應用一個規則-首先設置的規則。

例如,Oracle數據庫中有一個表:

1

2

3

4

5

6

7

8

CREATE TABLE NUMBER_TYPES

(

 ID NUMBER NOT NULL,

 VALUE1 NUMBER(5,2),

 VALUE2 NUMBER(10,4),

 VALUE3 NUMBER(15,6),

 CONSTRAINT PK_NUMBER_TYPES PRIMARY KEY (id)

)

TBCDField應用於NUMBER(10,4),TFMTBCDField - 應用於NUMBER(15,6),而不是默認字段:

UniDAC

若是按如下方式設置規則:

1

2

3

4

OraSession.DataTypeMap.Clear;

OraSession.DataTypeMap.AddDBTypeRule(oraNumber, 0,     9, rlAny, rlAny, ftFloat);

OraSession.DataTypeMap.AddDBTypeRule(oraNumber, 0, rlAny,     0,     4, ftBCD);

OraSession.DataTypeMap.AddDBTypeRule(oraNumber, 0, rlAny,     0, rlAny, ftFMTBCD);

結果以下:

UniDAC

可是,若是規則是按如下方式設置的:

1

2

3

4

OraSession.DataTypeMap.Clear;

OraSession.DataTypeMap.AddDBTypeRule(oraNumber, 0, rlAny,     0, rlAny, ftFMTBCD);

OraSession.DataTypeMap.AddDBTypeRule(oraNumber, 0, rlAny,     0,     4, ftBCD);

OraSession.DataTypeMap.AddDBTypeRule(oraNumber, 0,     9, rlAny, rlAny, ftFloat);

結果以下:

UniDAC

這是由於規則

1

OraSession.DataTypeMap.AddDBTypeRule(oraNumber, 0, rlAny, 0, rlAny, ftFMTBCD);

將應用於精度從0到無窮大,比例也從0到無窮大的數字字段。全部具備任何精度和刻度的數字字段都知足此條件。

使用數據類型映射時,將爲每一個類型搜索第一個匹配規則,並將其用於映射。在第二個示例中,第一個集合規則彷佛是全部三種類型的第一個匹配規則,所以ftFMTBCD類型將用於Delphi中的全部字段。

若是要返回到第一個示例,NUMBER(5,2)類型的第一個匹配規則是第一個規則,NUMBER(10,4)-第二個規則,NUMBER(15,6)-第三個規則。所以,在第一個例子中,獲得了預期的結果。

所以,應該記住,若是設置了數據類型映射規則,以便爲數據庫中的一個類型設置兩個或多個相互矛盾的規則,則這些規則將按指定的順序應用。

定義鏈接和數據集的規則

數據類型映射容許爲整個鏈接以及應用程序中的每一個數據集設置規則。

例如,這樣的表是在SQL Server中建立的:

1

2

3

4

5

6

7

8

9

10

CREATE TABLE person

(

 id                INT              NOT NULL  ,

 firstname         VARCHAR(20)          NULL  ,

 lastname          VARCHAR(30)          NULL  ,        

 gender_code       VARCHAR(1)           NULL  ,

 birth_dttm        DATETIME             NULL 

 CONSTRAINT pk_person PRIMARY KEY CLUSTERED (id ASCON [PRIMARY]

)

GO

衆所周知,birth_dttm字段包含birth day,該字段應該是delphi中的ftDate,而不是ftDateTime。若是設置了此規則:

1

2

MSConnection.DataTypeMap.Clear;

MSConnection.DataTypeMap.AddDBTypeRule(msDateTime, ftDate);

Delphi中的全部日期時間字段都將具備ftDate類型,這是不正確的。ftDate類型只能在處理person表時用於DATETIME類型。在這種狀況下,不該爲整個鏈接設置數據類型映射,而應爲特定的數據集設置:

1

2

MSQuery.DataTypeMap.Clear;

MSQuery.DataTypeMap.AddDBTypeRule(msDateTime, ftDate);

或者相反的狀況。例如,DATETIME在應用程序中僅用於日期存儲,而且只有一個表同時存儲日期和時間。在這種狀況下,如下規則設置將是正確的:

1

2

3

4

MSConnection.DataTypeMap.Clear;

MSConnection.DataTypeMap.AddDBTypeRule(msDateTime, ftDate);

MSQuery.DataTypeMap.Clear;

MSQuery.DataTypeMap.AddDBTypeRule(msDateTime, ftDateTime);

在這種狀況下,將爲ftDate類型的DATETIME類型字段和ftDateTime類型的MSQuery建立全部數據集。

重點是,爲數據集設置的規則的優先級高於爲整個鏈接設置的規則的優先級。這容許爲整個應用程序靈活方便地設置數據類型映射。不須要爲每一個數據集設置相同的規則,全部常規規則均可覺得整個鏈接設置一次。若是須要具備單個數據類型映射的數據集,能夠爲其設置單個規則。

特定字段的規則

有時須要設置一個規則,不是針對整個鏈接,也不是針對整個數據集,而是僅針對特定字段。

例如,MySQL 數據庫中有這樣的表:

1

2

3

4

5

6

7

CREATE TABLE item

(

 id INT NOT NULL AUTO_INCREMENT,

 name CHAR(50) NOT NULL,

 guid CHAR(38),

 PRIMARY KEY (id)

) ENGINE=MyISAM;

guid字段包含惟一標識符。爲了方便工做,此標識符應映射到Delphi中的TGuidField類型。可是有一個問題,若是要設置這樣的規則:

1

2

MyQuery.DataTypeMap.Clear;

MyQuery.DataTypeMap.AddDBTypeRule(myChar, ftGuid);

而後,name和guid字段都將在delphi中具備ftguid類型,這與計劃的內容不符。在這種狀況下,惟一的方法是對特定字段使用數據類型映射:

1

MyQuery.DataTypeMap.AddFieldNameRule('guid', ftGuid);

此外,必須記住,爲特定字段設置規則具備最高優先級。若是要爲特定字段設置某些規則,則鏈接或數據集中的全部其餘規則都將被此字段忽略。

忽略轉換錯誤

數據類型映射容許映射各類類型,有時會出現這樣的問題:存儲在數據庫中的數據沒法轉換爲數據類型映射規則中指定的Delphi字段類型的正確數據,反之亦然。在這種狀況下,將發生一個錯誤,這將通知數據沒法映射到指定的類型。

例如:

UniDAC

但在爲數據類型映射設置規則時,有可能忽略數據轉換錯誤:

1

IBCConnection.DataTypeMap.AddDBTypeRule(ibcVarchar, ftInteger, True);

在這種狀況下,不可能進行正確的轉換。可是因爲忽略了數據轉換錯誤,數據類型映射嘗試返回能夠根據轉換方向設置爲Delphi字段或DB字段的值。

UniDAC

所以,只有在預期轉換結果時才應使用忽略轉換錯誤。

UniDAC和數據類型映射

當使用UniDAC時,常常會出現一種難以解決的狀況,即數據庫中的兩個類似類型在Delphi中有不一樣的類型。爲了更清楚地說明,下面有一些例子。

例如,有一個項目,它與兩個DB一塊兒工做:Oracle和SQL Server。在每一個數據庫中都建立了這樣的表:

Oracle:

1

2

3

4

5

6

7

CREATE TABLE ITEM_INFO

(

 ID NUMBER NOT NULL,

 CODE VARCHAR2(10)  NOT NULL,

 DESCRIPTION NVARCHAR2(250),

 CONSTRAINT PK_ITEM_INFO PRIMARY KEY (id)

)

SQL Server:

1

2

3

4

5

6

7

8

9

CREATE TABLE item_info

(

 id                INT              NOT NULL  ,

 code              VARCHAR(10)      NOT NULL  ,

 description       NVARCHAR(250)        NULL  ,        

 CONSTRAINT pk_item_info PRIMARY KEY CLUSTERED (id ASC)

 ON [PRIMARY]

)

GO

問題在於,使用啓用的UseUnicode選項處理Oracle時,代碼和描述字段都將具備ftWideString類型,若是禁用了UseUnicode選項,這兩個字段都將具備ftString類型。對於SQL Server,代碼字段始終是ftString,描述字段始終是ftWideString。當試圖建立持久字段時,這個問題尤爲嚴重,由於在這種狀況下,當與某個提供程序一塊兒工做時,老是會發生錯誤。之前,避免錯誤的惟一方法是在這種狀況下拒絕使用持久字段。

目前,這個問題很容易解決。能夠爲Oracle提供程序設置數據類型映射:

1

2

3

UniConnection.DataTypeMap.Clear;

UniConnection.DataTypeMap.AddDBTypeRule(oraVarchar2, ftString);

UniConnection.DataTypeMap.AddDBTypeRule(oraNVarchar2, ftWideString);

或者能夠爲SQL Server設置數據類型映射:

1

2

3

// for useUnicode = True in the Oracle data provider

UniConnection.DataTypeMap.Clear;

UniConnection.DataTypeMap.AddDBTypeRule(msVarchar, ftWideString);

或者:

1

2

3

// for useUnicode = False in the Oracle data provider

UniConnection.DataTypeMap.Clear;

UniConnection.DataTypeMap.AddDBTypeRule(msNVarchar, ftString);

相關文章
相關標籤/搜索