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等等)。这意味着您可以在您的项目之间轻松地切换不同的数据库,以及创建跨数据库应用程序接口。

概述

Data Type Mapping数据类型映射是一种灵活且易于定制的工具,它允许在DB类型和Delphi字段类型之间进行映射。

在本文中,有几个示例,可以在处理所有支持的DBS时使用。为了清楚地显示数据类型映射设备的通用性,每个示例将使用单独的数据库。

数据类型映射规则

在不支持数据类型映射的版本中,UniDAC自动设置DB数据类型和Delphi 字段类型之间的对应关系。在具有数据类型映射的版本中,可以手动设置DB数据类型和Delphi 字段类型之间的对应关系。

下面是PostgreSQL数据库下表中数字类型的示例:

1

2

3

4

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

转载于:https://my.oschina.net/u/4009527/blog/3007687

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值