Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Firebird UUID <> GUID (https://www.delphipraxis.net/172670-firebird-uuid-guid.html)

Morphie 16. Jan 2013 18:53

Datenbank: Firebird • Version: 2.5.2 • Zugriff über: ADO.NET

Firebird UUID <> GUID
 
Hi,

ich habe mich aus diversen Gründen dafür entschieden, die Primärschlüssel in meiner Datenbank als UUID abzubilden.
Die UUID-Domain ist (wie hier beschrieben) in Firebird wie folgt deklariert:
Code:
CREATE DOMAIN UUID AS
  CHAR(16)
  CHARACTER SET OCTETS;
Die Felder versehe ich mit folgendem Comment:
Code:
#GUID#
Ab sofort erkennt das EntityFramework die Felder als GUIDs und mappt diese entsprechend.
Die GUIDs vergebe ich im Constructor der Entities auf der Client-Seite.

Jetzt zum Problem:
Heute habe ich mehrere Stunden damit verbracht, herauszufinden, warum das EF meine Datensätze beim Refresh nicht wiederfindet.
Zuerst hatte ich den ADO.NET Provider in Verdacht, doch dann stelle sich heraus, dass der nicht schuld war. Er überträgt schon die richtigen Werte.

Das EntityFramework setzt beim Refresh-Befehl folgenden SQL-Query ab:
Code:
SELECT
"B"."ID" AS "ID",
"B"."BEZEICHNUNG" AS "BEZEICHNUNG"
FROM "ZAHLUNGSARTEN" AS "B"
WHERE "B"."ID" = CHAR_TO_UUID('a6ddceee-dc33-46cc-9378-75fbc4d87ef2')
Folgende GUID hat mein Objekt also als Primärschlüssel:
Code:
a6ddceee-dc33-46cc-9378-75fbc4d87ef2
oder in folgende 16 Codes ausgedrückt:
Code:
238,206,221,166,51,220,204,70,147,120,117,251,196,216,126,242
Stelle ich diese Bytes aber in Firebird mittels UUID_TO_CHAR dar, so wie es die SQL-Abfrage macht, bekomme ich eine andere Zeichenfolge, nämlich diese:
Code:
EECEDDA6-33DC-CC46-9378-75FBC4D87EF2
UUID_TO_CHAR bildet also einen falschen / anderen String ab. Dann ist es auch klar, warum das EntityFramework meine Datensätze nicht wiederfindet...

Jetzt die Frage:
Ist das ein Bug in Firebird?
Laut den Release-Notes hat sich in FB 2.5.2 etwas an dem Algorithmus geändert, doch das behebt mein Problem leider nicht.

Oder gibt es wirklich einen Unterschied zwischen UUID und GUID?
Gibt es eine UDF, um die richtige GUID-Zeichenfolge abbilenden zu können?

Oder wäre es vielleicht besser, doch den ADO.NET Firebird Provider umzuschreiben, so dass er nicht mehr UUID_TO_CHAR aufruft, sondern die GUID als Byte-Array per Paramater übergibt? Und wenn ja, wie geht das?! ;-)

Ich hoffe mir kann hier jemand helfen, falls jemand diese doch recht spezielle Frage überhaupt versteht ;-)

Bummi 16. Jan 2013 21:07

AW: Firebird UUID <> GUID
 
Die ersten 3 Blöcke scheinen "invertiert" die restlichen 2 nicht "invertiert".

http://stackoverflow.com/questions/2...uid-and-a-uuid

Morphie 17. Jan 2013 07:11

AW: Firebird UUID <> GUID
 
Ja, das ist mir auch aufgefallen... Die ersten 3 Blöcke sind in je 2-Char-Blöcke invertiert...
Diese erkenntnis hilft mir aber leider bis jetzt noch nicht :-(

Lemmy 17. Jan 2013 14:27

AW: Firebird UUID <> GUID
 
Hallo,

Problem kann ich mit Firebird 2.5.2.26539 embedded und Flamerobin nicht nachvollziehen. Hast Du die DB mit 2.5.2 angelegt? Hier soll es ja zwischen 2.5 und 2.5.2 wirklich unterschiedliche Rückgabewerte geben.
Code:

CREATE TABLE TEST
(
  GUID char(36),
  UUID char(16) CHARACTER SET OCTETS
);

INSERT INTO TEST (GUID, UUID)
VALUES (
    '9B7C3C32-2B51-49D5-BB9A-7C044B91A061',
    CHAR_TO_UUID('9B7C3C32-2B51-49D5-BB9A-7C044B91A061')
);

select guid, UUID_TO_CHAR(UUID) from test;

ergibt:

9B7C3C32-2B51-49D5-BB9A-7C044B91A061   9B7C3C32-2B51-49D5-BB9A-7C044B91A061

Morphie 17. Jan 2013 14:46

AW: Firebird UUID <> GUID
 
ja, ich habe es mit 2.5.2 ansprobiert.

Du hast das Problem in deinem Beispiel nicht, weil du die 16-Byte UUID bereits mittels CHAR_TO_UUID('9B7C3C32-2B51-49D5-BB9A-7C044B91A061') anlegst...

Das Problem tritt auf, wenn man (z.B. in .NET) eine Variable vom Typ Guid hat. Wenn man sich diesen als 36-Zeichen String ausgeben lässt, bekommt man z.B. diese Darstellung:
Code:
a6ddceee-dc33-46cc-9378-75fbc4d87ef2
Intern speichert Guid aber ein Array von 16 Bytes.
Code:
238,206,221,166,51,220,204,70,147,120,117,251,196,216,126,242
Legt man jetzt einen Datensatz an und will die 16-Byte UUID übergeben, macht man das so:
Code:
INSERT INTO TABLE (ID) VALUES (@PARAMETER1)
im Parameter1 übergibt man dann das 16-Byte-Array. Hier unterscheidet sich dein Beispiel von meinem. Du übergibst die UUID mittels der (ebenfalls fehlerhaften) Funktion CHAR_TO_UUID. Diese beiden Fehler heben sich gegenseitig auf.
Übergibt man die UUID immer über den Befehl CHAR_TO_UUID merkt man den Fehler nicht. Übergibt man ihn dann irgendwann mal als Parameter, hat man das Problem.


In der Datenbank stehen anschließend im Feld ID genau diese 16 Bytes drin. Das kann man sich auch ganz gut mit folgender Abfrage ansehen:
Code:
select
ascii_val(substring(Tabelle.id from 1 for 1)),
ascii_val(substring(Tabelle.id from 2 for 1)),
ascii_val(substring(Tabelle.id from 3 for 1)),
ascii_val(substring(Tabelle.id from 4 for 1)),
ascii_val(substring(Tabelle.id from 5 for 1)),
ascii_val(substring(Tabelle.id from 6 for 1)),
ascii_val(substring(Tabelle.id from 7 for 1)),
ascii_val(substring(Tabelle.id from 8 for 1)),
ascii_val(substring(Tabelle.id from 9 for 1)),
ascii_val(substring(Tabelle.id from 10 for 1)),
ascii_val(substring(Tabelle.id from 11 for 1)),
ascii_val(substring(Tabelle.id from 12 for 1)),
ascii_val(substring(Tabelle.id from 13 for 1)),
ascii_val(substring(Tabelle.id from 14 for 1)),
ascii_val(substring(Tabelle.id from 15 for 1)),
ascii_val(substring(Tabelle.id from 16 for 1))
from Tabelle
Konvertiert man diese Bytes anschließend wieder mittels UUID_TO_CHAR zurück, bekommt man einen vom original-.NET.GUID-String abweichenden String:
Code:
EECEDDA6-33DC-CC46-9378-75FBC4D87EF2


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:28 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz