翻譯|使用教程|編輯:李爽夏|2019-01-31 09:59:27.000|閱讀 461 次
概述:本篇文章介紹使用UniDAC中的數(shù)據(jù)類型映射。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關(guān)鏈接:
Universal Data Access Components (UniDAC)是一款通用數(shù)據(jù)庫訪問組件,提供了多個(gè)數(shù)據(jù)庫的直接訪問,如針對Windows的Delphi, C++Builder, Lazarus (以及 Free Pascal) , Mac OS X, iOS, Android, Linux和64和32位的FreeBSD等等。我們將長期的經(jīng)驗(yàn)集于這個(gè)小組件,提供統(tǒng)一的數(shù)據(jù)庫連接訪問(如oracle、微軟SQL等等)。這意味著您可以在您的項(xiàng)目之間輕松地切換不同的數(shù)據(jù)庫,以及創(chuàng)建跨數(shù)據(jù)庫應(yīng)用程序接口。
Data Type Mapping(數(shù)據(jù)類型映射)是一種靈活且易于定制的工具,它允許在DB類型和Delphi字段類型之間進(jìn)行映射。
在本文中,有幾個(gè)示例,可以在處理所有支持的DBS時(shí)使用。為了清楚地顯示數(shù)據(jù)類型映射設(shè)備的通用性,每個(gè)示例將使用單獨(dú)的數(shù)據(jù)庫。
在不支持?jǐn)?shù)據(jù)類型映射的版本中,UniDAC自動設(shè)置DB數(shù)據(jù)類型和Delphi 字段類型之間的對應(yīng)關(guān)系。在具有數(shù)據(jù)類型映射的版本中,可以手動設(shè)置DB數(shù)據(jù)類型和Delphi 字段類型之間的對應(yīng)關(guān)系。
下面是PostgreSQL數(shù)據(jù)庫下表中數(shù)字類型的示例:
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) )
應(yīng)使用數(shù)據(jù)類型映射,以便:
Delphi中Scale=0的數(shù)字字段將映射到以下字段類型之一:TSmallintField、TIntegerField 或TlargeintField,具體取決于精度
為了保存精度,Precision>=10且Scalе<= 4的數(shù)字字段將映射到TBCDField。
數(shù)值字段Scalе>= 5將映射到TFMTBCDField。
以上表格形式:
要指定Precision <= 4且Scale = 0的數(shù)值字段必須映射到ftSmallint,應(yīng)設(shè)置以下規(guī)則:
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;
這是詳細(xì)規(guī)則設(shè)置的一個(gè)例子,它是為了最大限度地可視化而設(shè)計(jì)的。通常,規(guī)則設(shè)置得要短得多,例如如下所示:
// 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);
在設(shè)置規(guī)則時(shí),可能會出現(xiàn)這樣的情況:為數(shù)據(jù)庫中的一個(gè)類型設(shè)置了兩個(gè)或多個(gè)相互矛盾的規(guī)則。在這種情況下,將只應(yīng)用一個(gè)規(guī)則-首先設(shè)置的規(guī)則。
例如,Oracle數(shù)據(jù)庫中有一個(gè)表:
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應(yīng)用于NUMBER(10,4),TFMTBCDField - 應(yīng)用于NUMBER(15,6),而不是默認(rèn)字段:
如果按以下方式設(shè)置規(guī)則:
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);
結(jié)果如下:
但是,如果規(guī)則是按以下方式設(shè)置的:
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);
結(jié)果如下:
這是因?yàn)橐?guī)則
OraSession.DataTypeMap.AddDBTypeRule(oraNumber, 0, rlAny, 0, rlAny, ftFMTBCD);
將應(yīng)用于精度從0到無窮大,比例也從0到無窮大的數(shù)字字段。所有具有任何精度和刻度的數(shù)字字段都滿足此條件。
使用數(shù)據(jù)類型映射時(shí),將為每個(gè)類型搜索第一個(gè)匹配規(guī)則,并將其用于映射。在第二個(gè)示例中,第一個(gè)集合規(guī)則似乎是所有三種類型的第一個(gè)匹配規(guī)則,因此ftFMTBCD類型將用于Delphi中的所有字段。
如果要返回到第一個(gè)示例,NUMBER(5,2)類型的第一個(gè)匹配規(guī)則是第一個(gè)規(guī)則,NUMBER(10,4)-第二個(gè)規(guī)則,NUMBER(15,6)-第三個(gè)規(guī)則。因此,在第一個(gè)例子中,得到了預(yù)期的結(jié)果。
因此,應(yīng)該記住,如果設(shè)置了數(shù)據(jù)類型映射規(guī)則,以便為數(shù)據(jù)庫中的一個(gè)類型設(shè)置兩個(gè)或多個(gè)相互矛盾的規(guī)則,則這些規(guī)則將按指定的順序應(yīng)用。
數(shù)據(jù)類型映射允許為整個(gè)連接以及應(yīng)用程序中的每個(gè)數(shù)據(jù)集設(shè)置規(guī)則。
例如,這樣的表是在SQL Server中創(chuàng)建的:
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 ASC) ON [PRIMARY] ) GO
眾所周知,birth_dttm字段包含birth day,該字段應(yīng)該是delphi中的ftDate,而不是ftDateTime。如果設(shè)置了此規(guī)則:
MSConnection.DataTypeMap.Clear; MSConnection.DataTypeMap.AddDBTypeRule(msDateTime, ftDate);
Delphi中的所有日期時(shí)間字段都將具有ftDate類型,這是不正確的。ftDate類型只能在處理person表時(shí)用于DATETIME類型。在這種情況下,不應(yīng)為整個(gè)連接設(shè)置數(shù)據(jù)類型映射,而應(yīng)為特定的數(shù)據(jù)集設(shè)置:
MSQuery.DataTypeMap.Clear; MSQuery.DataTypeMap.AddDBTypeRule(msDateTime, ftDate);
或者相反的情況。例如,DATETIME在應(yīng)用程序中僅用于日期存儲,并且只有一個(gè)表同時(shí)存儲日期和時(shí)間。在這種情況下,以下規(guī)則設(shè)置將是正確的:
MSConnection.DataTypeMap.Clear; MSConnection.DataTypeMap.AddDBTypeRule(msDateTime, ftDate); MSQuery.DataTypeMap.Clear; MSQuery.DataTypeMap.AddDBTypeRule(msDateTime, ftDateTime);
在這種情況下,將為ftDate類型的DATETIME類型字段和ftDateTime類型的MSQuery創(chuàng)建所有數(shù)據(jù)集。
重點(diǎn)是,為數(shù)據(jù)集設(shè)置的規(guī)則的優(yōu)先級高于為整個(gè)連接設(shè)置的規(guī)則的優(yōu)先級。這允許為整個(gè)應(yīng)用程序靈活方便地設(shè)置數(shù)據(jù)類型映射。不需要為每個(gè)數(shù)據(jù)集設(shè)置相同的規(guī)則,所有常規(guī)規(guī)則都可以為整個(gè)連接設(shè)置一次。如果需要具有單個(gè)數(shù)據(jù)類型映射的數(shù)據(jù)集,可以為其設(shè)置單個(gè)規(guī)則。
有時(shí)需要設(shè)置一個(gè)規(guī)則,不是針對整個(gè)連接,也不是針對整個(gè)數(shù)據(jù)集,而是僅針對特定字段。
例如,MySQL 數(shù)據(jù)庫中有這樣的表:
CREATE TABLE item ( id INT NOT NULL AUTO_INCREMENT, name CHAR(50) NOT NULL, guid CHAR(38), PRIMARY KEY (id) ) ENGINE=MyISAM;
guid字段包含唯一標(biāo)識符。為了方便工作,此標(biāo)識符應(yīng)映射到Delphi中的TGuidField類型。但是有一個(gè)問題,如果要設(shè)置這樣的規(guī)則:
MyQuery.DataTypeMap.Clear; MyQuery.DataTypeMap.AddDBTypeRule(myChar, ftGuid);
然后,name和guid字段都將在delphi中具有ftguid類型,這與計(jì)劃的內(nèi)容不符。在這種情況下,唯一的方法是對特定字段使用數(shù)據(jù)類型映射:
MyQuery.DataTypeMap.AddFieldNameRule('guid', ftGuid);
此外,必須記住,為特定字段設(shè)置規(guī)則具有最高優(yōu)先級。如果要為特定字段設(shè)置某些規(guī)則,則連接或數(shù)據(jù)集中的所有其他規(guī)則都將被此字段忽略。
數(shù)據(jù)類型映射允許映射各種類型,有時(shí)會出現(xiàn)這樣的問題:存儲在數(shù)據(jù)庫中的數(shù)據(jù)無法轉(zhuǎn)換為數(shù)據(jù)類型映射規(guī)則中指定的Delphi字段類型的正確數(shù)據(jù),反之亦然。在這種情況下,將發(fā)生一個(gè)錯誤,這將通知數(shù)據(jù)無法映射到指定的類型。
例如:
但在為數(shù)據(jù)類型映射設(shè)置規(guī)則時(shí),有可能忽略數(shù)據(jù)轉(zhuǎn)換錯誤:
IBCConnection.DataTypeMap.AddDBTypeRule(ibcVarchar, ftInteger, True);
在這種情況下,不可能進(jìn)行正確的轉(zhuǎn)換。但是由于忽略了數(shù)據(jù)轉(zhuǎn)換錯誤,數(shù)據(jù)類型映射嘗試返回可以根據(jù)轉(zhuǎn)換方向設(shè)置為Delphi字段或DB字段的值。
因此,只有在預(yù)期轉(zhuǎn)換結(jié)果時(shí)才應(yīng)使用忽略轉(zhuǎn)換錯誤。
當(dāng)使用UniDAC時(shí),經(jīng)常會出現(xiàn)一種難以解決的情況,即數(shù)據(jù)庫中的兩個(gè)相似類型在Delphi中有不同的類型。為了更清楚地說明,下面有一些例子。
例如,有一個(gè)項(xiàng)目,它與兩個(gè)DB一起工作:Oracle和SQL Server。在每個(gè)數(shù)據(jù)庫中都創(chuàng)建了這樣的表:
Oracle:
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:
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選項(xiàng)處理Oracle時(shí),代碼和描述字段都將具有ftWideString類型,如果禁用了UseUnicode選項(xiàng),這兩個(gè)字段都將具有ftString類型。對于SQL Server,代碼字段始終是ftString,描述字段始終是ftWideString。當(dāng)試圖創(chuàng)建持久字段時(shí),這個(gè)問題尤其嚴(yán)重,因?yàn)樵谶@種情況下,當(dāng)與某個(gè)提供程序一起工作時(shí),總是會發(fā)生錯誤。以前,避免錯誤的唯一方法是在這種情況下拒絕使用持久字段。
目前,這個(gè)問題很容易解決。可以為Oracle提供程序設(shè)置數(shù)據(jù)類型映射:
UniConnection.DataTypeMap.Clear; UniConnection.DataTypeMap.AddDBTypeRule(oraVarchar2, ftString); UniConnection.DataTypeMap.AddDBTypeRule(oraNVarchar2, ftWideString);
或者可以為SQL Server設(shè)置數(shù)據(jù)類型映射:
// for useUnicode = True in the Oracle data provider UniConnection.DataTypeMap.Clear; UniConnection.DataTypeMap.AddDBTypeRule(msVarchar, ftWideString);
或者:
// for useUnicode = False in the Oracle data provider UniConnection.DataTypeMap.Clear; UniConnection.DataTypeMap.AddDBTypeRule(msNVarchar, ftString);
購買UniDAC正版授權(quán),請點(diǎn)擊“”喲!
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn