FireBird 数据库里面没有专门的 GUID 类型的字段。采用字段类型为:Char(16) OCTETS 可以存储 GUID;
在 Delphi 里面,用 FireDAC FdQuery 去打开有这个字段的表,对应的字段类型是:TBytesField;强行将这个字段改为 TGUIDField 类型的字段,打开表会出现类型不匹配的异常;同样,ClientDataSet 里面对应的字段类型也是 TBytesField,不能强制为 TGUIDField 类型的字段;
如果某个 ClientDataSet 里面,有 TGUIDField 类型的字段,比如字段名叫:ID, 对这个字段进行 Locate 搜索,不会出现异常,但定位不到。如果用 FindKey 可以定位到,但必须先指定这个字段是 Index 字段。代码如下:
function VarFromGuid(const aGuid: TGuid): Variant;
var
Ptr: Pointer;
begin
Result := VarArrayCreate( [1, Sizeof(aGuid)], varByte);
Ptr := VarArrayLock(Result);
try
Move(aGuid, Ptr^, Sizeof(aGuid));
finally
VarArrayUnlock(Result);
end;
end;
上述函数是把 GUID 转换为 Variant,因为 DataSet.Locate 需要的参数类型是 variant 类型。
procedure TForm1.Button7Click(Sender: TObject);
var
G: TGUID;
S: string;
V: Variant;
begin
//这里的 ID 字段是 TGUIDField 类型
S := Edit2.Text;
G := StringToGUID(S);
V := VarFromGUID(G);
with ClientDataSet2 do
begin
Locate('ID',varArrayOf([V]) , []); //定位不到。但执行不会出异常。
//ClientDataSet2.FindKey([S]); //可以定位到。
end;
end;
-----------------------------------
如果 ClientDataSet 的字段类型是 TBytesField,则不能执行 Locate('ID',varArrayOf([V]) , []); 方法,运行时会提示不支持的类型。
但对于 FireDAC,FdMemTable 如果有字段是 TBytesField 类型,可以执行 Locate('ID',varArrayOf([V]) , []) 方法能够成功搜索到。
对ClientDataSet 的 TBytesField 字段,执行 FindKey 方法可以成功定位。代码如下:
procedure TForm1.Button5Click(Sender: TObject);
var
G: TGUID;
S: string;
V: Variant;
begin
//这里的 M_ID 字段是 TBytesField 类型,对应的是 FireBird 里面的 Char(16) OCTETS 类型字段
S := '{F3E75FED-5C47-439D-A5BE-913EF9457577}';
G := StringToGUID(S);
V := VarFromGUID(G);
{ 以下代码对 FdMemTable1 进行 Locate 成功。
FdQuery1.Open();
FDMemTable1.CopyDataSet(ClientDataSet1);
DataSource1.DataSet := FDMemTable1;
with FDMemTable1 do
begin
Locate('M_ID', varArrayOf([VarFromGuid(G)]), []);
end;
}
with ClientDataSet1 do
begin
//Locate('M_ID',varArrayOf([V]) , []); // 会出现异常
FindKey([V]);
end;
end;
对应的 TBytesField,直接写入 GUID 成功:
procedure TForm1.Button3Click(Sender: TObject);
begin
//M_ID 是 TBytesField 类型的字段,写入成功
with ClientDataSet1 do
begin
Insert;
FieldByName('M_ID').AsGuid := Self.GetGUID;
Post;
end;
end;
又:
如果是 FdMemTable,同样的 TBytesField 字段,采用上述 Locate 方法,可以成功定位。
因此,FdMemTable 比 ClientDataSet 确实好用一些。
SQL 查询:
在 Firebird 中对该 GUID 字段进行 query:select * from MATERIAL where M_ID=:MID
使用 FdQuery 控件,测试成功:
procedure TForm1.Button4Click(Sender: TObject);
begin
//能够成功搜索到正确记录
with FdQuery2 do
begin
Close;
Params[0].AsGUID := StringToGUID('{F3E75FED-5C47-439D-A5BE-913EF9457577}');
Open;
DataSource1.DataSet := FdQuery2;
end;
end;
总结:
可以在 Firebird 数据库中采用16字节的 OCTETS 类型的字段来存储 GUID,比存储字符串格式的GUID要节约很多空间;字符串格式要36个字节.
对应到 Delphi 的 DataSet 的字段类型,是 TBytesField。可以在运行期采用 Field.AsGUID 的方式写入 TGUID 类型的数据,提交成功。
对于 FdQuery 和 FdMemTable 来说,上述 TBytesField 字段,可以进行 Locate,需要先把GUID参数转换为 Variant。
对于 ClientDataSet 来说,对 TBytesField 字段进行 Locate 会出现异常;对 TGUIDField 自动进行 Locate 不会出现异常但定位不到。但是,采用 FindKey 方法来定位,成功。因此对应 Firebird 数据库的 GUID 字段,ClientDataSet 可以使用 FindKey 的方式。需要注意的是,DataSet.FindKey 的字段,必须是索引字段。

探讨在FireBird数据库中使用16字节OCTETS类型存储GUID的方法,节省空间并提高效率。通过Delphi的TBytesField与TGUIDField进行数据读写,解析Locate与FindKey定位差异。
550

被折叠的 条评论
为什么被折叠?



