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);

相关文章
相关标签/搜索