Hi there,
My guids in Firebird are with the format : MYGUID = CHAR(16) CHARACTER SET OCTETS; It’s the recommended GUID format for Interbase.
In table PERSON I have a field ID MYGUID.
This field is recognized as a BLOB by data abstract, and if I manually assign the GUID type to the field, I have errors saying this is a bad GUID.
FireDAC normally recognizes this. It detects the field as a TBytesField, and if the assigned domain name has the substring GUID in it (when the connection fetches ExtendedMetadata), it casts the TBytesField to TGUIDField. Then, when using that field in a table, FireDAC automatically sets the display text to human readable GUIDs instead of bytes.
I can’t store the GUIDs as plain string as it has bad impacts on indexing and other performance reasons.
Could you plan on supporting bytes guids ?
Thank you
Edit
Also, I can’t even use the blob ids. When I do so, i get an error
Exception ‘first chance’ à $764E5B68. Classe d’exception EDatabaseError avec un message ‘Le champ ‘PERSON_ID’ ne peut être un champ calculé ni un champ référence’. Processus EntiteREM2.exe (6504)
(The field 'PERSON_ID' cannot be a calculated field or a reference field)
:764e5b68 KERNELBASE.RaiseException + 0x48
Data.DB.DatabaseError('Le champ ''PERSON_ID'' ne peut être un champ calculé ni un champ référence',???)
Data.DB.DatabaseErrorFmt('Le champ ''%s'' ne peut être un champ calculé ni un champ référence',(...),nil)
uDAMemDataset.TDAMemoryDataset.ValidateFieldForIndex($2B40AD0)
uDAMemDataset.TDAMemIndex.Init('PERSON_ID','','')
uDAMemDataset.TDAMemIndex.Init('PERSON_ID',False,False)
uDAMemDataset.TDAMemoryDataset.intDirectSearch('PERSON_ID','âγFú'#$009D'žJ†'#7'ñËÊêÝ{',[],True,$4C414A0)
uDAMemDataset.TDAMemoryDataset.LocateRecord('PERSON_ID','âγFú'#$009D'žJ†'#7'ñËÊêÝ{',[],True,$4C414A0)
uDAMemDataset.TDAMemoryDataset.Locate('PERSON_ID','âγFú'#$009D'žJ†'#7'ñËÊêÝ{',[])
uDADataTable.TDADataTable.Locate('PERSON_ID',Variant array of Variant,[])
uDADataTable.TDADataTable.MergeDelta
uDADataAdapter.TDABaseDataAdapter.InternalApplyUpdates_ThrowFailures($4BF0798)
uDADataAdapter.TDABaseDataAdapter.InternalApplyUpdatesAndThrowFailures($4BF0768,$4BF07B0)
uDADataAdapter.TDABaseDataAdapter.ApplyUpdates(???,False)
uDADataTable.TDADataTable.InternalApplyUpdates(True)
uDADataTable.TDADataTable.ApplyUpdates(False,True)
fClientForm.TClientForm.ActionApplyUpdatesExecute($2BFEE50)
System.Classes.TBasicAction.Execute
Vcl.ActnList.TCustomAction.Execute
System.Classes.TBasicActionLink.Execute(???)
dxBar.TdxBarItem.DoClick
dxBar.TdxBarItem.DirectClick
dxBar.TdxBarItemControl.ControlUnclick(True)
dxBar.TdxBarButtonControl.ControlUnclick(True)
dxBar.TCustomdxBarControl.DoLButtonUp((514, (), 0, (), 83, 4, (), (83, 4), (), 0))
dxBar.TdxBarControl.DoLButtonUp((514, (), 0, (), 83, 4, (), (83, 4), (), 0))
dxBar.TCustomdxBarControl.WMLButtonUp((514, (), 0, (), 83, 4, (), (83, 4), (), 0))
dxBar.TdxBarDockedControl.WMLButtonUp((514, (), 0, (), 83, 4, (), (83, 4), (), 0))
Vcl.Controls.TControl.WndProc((514, 0, 262227, 0, 0, 0, (), 83, 4, (), 0, 0, ()))
Vcl.Controls.TWinControl.WndProc((514, 0, 262227, 0, 0, 0, (), 83, 4, (), 0, 0, ()))
dxBar.TCustomdxBarControl.WndProc((514, 0, 262227, 0, 0, 0, (), 83, 4, (), 0, 0, ()))
dxBar.TdxBarControl.WndProc((514, 0, 262227, 0, 0, 0, (), 83, 4, (), 0, 0, ()))
Vcl.Controls.TWinControl.MainWndProc(???)
System.Classes.StdWndProc(2690036,514,0,262227)
:75e38e71 user32.CallNextHookEx + 0xb1
:75e390d1 ; C:\Windows\SysWOW64\user32.dll
:75e3a66f ; C:\Windows\SysWOW64\user32.dll
:75e3a6e0 user32.DispatchMessageW + 0x10
Vcl.Forms.TApplication.ProcessMessage(???)
:006269e8 TApplication.ProcessMessage + $F8
EDIT 1
I got it working by changing the field definition in SchemaModeler from BLOB to FixedChar(16). It would still be nice to not have to do this manually, as everytime I refresh the field defs in Schema Modeler, I have to manually change again the BLOB to FixedChar.
Also, could it still be possible to map this kind of data to a standard TGuid data type? Because now when I add a new record, I have to run this for each table (OnNewRecord) :
procedure TClientDataModule.NewRecordGuid(DataTable: TDADataTable);
var
aCollectionItem: TCollectionItem;
aField: TDAField;
begin
for aCollectionItem in DataTable.Fields do
if aCollectionItem is TDAField then
begin
aField := TDAField(aCollectionItem);
if (aField.InPrimaryKey) and (aField.DataType = datFixedChar) and (aField.Size = 16) then
aField.AsString := GetGuidString;
end;
end;
And this for GetText of every guid field
procedure TClientDataModule.GuidGetText(Sender: TDACustomField; var Text: string; DisplayText: Boolean);
begin
Text := GUIDToString(TGuid.Create(TEncoding.Default.GetBytes(Sender.Value)));
end;