I\'m having difficulties manually debugging an .NET application where the Guid values differ from .NET to Oracle.
17D89D326C2142
If you need to convert a GUID to RAW from PL/SQL can use this function:
/*
CONVERT a GUID FORMAT in RAW(16)
EX:
guid = 88c6a267-65d2-48d6-8da2-6f45e2c22726
raw = 67A2C688D265D6488DA26F45E2C22726
*/
FUNCTION GuidToRaw( guid IN VARCHAR2 ) RETURN RAW
IS
ret RAW(16);
guidHex VARCHAR2(64);
BEGIN
guidHex := SUBSTR (guid, 7, 2);
guidHex := CONCAT( guidHex, SUBSTR (guid, 5, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 3, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 1, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 12, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 10, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 17, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 15, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 20, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 22, 2) );
guidHex := CONCAT( guidHex, SUBSTR (guid, 25, 12) );
ret := HEXTORAW( guidHex );
return ret;
end;
If you look at the values involved (in pairs) of hex digits you can see that the last 7 bytes are the same in both cases, but the first 9 are switched around a bit.
Going from your example, but rewriting each pair in the .NET as 00, 11, 22 etc and switching the relevant byte of Oracle as well we get:
.NET:
00112233445566778899AABBCCDDEEFF
Oracle:
33221100554477668899AABBCCFFEEFF
So it should be fairly easy to write code to switch round the relevant bytes. (I'm pretty sure I wrote some code to do this in a previous job, in fact.)
To switch round the bytes, you'll just want to call Guid.ToByteArray()
and new Guid(byte[])
to get back to a Guid
.
EDIT: As it happens, the switch-round above is exactly what the Guid
constructor does when you pass it a byte array:
using System;
using System.Linq;
class Test
{
static void Main()
{
byte[] bytes = Enumerable.Range(0, 16)
.Select(x => x * 16 + x)
.Select(x => (byte) x)
.ToArray();
Console.WriteLine(BitConverter.ToString(bytes).Replace("-", ""));
Console.WriteLine(new Guid(bytes).ToString().Replace("-", ""));
}
}
Prints:
00112233445566778899AABBCCDDEEFF
33221100554477668899aabbccddeeff
That may well make it considerably simpler to perform the switching... how were you getting hold of the values to start with? Is it just "how they're displayed in Oracle"?
EDIT: Okay, here are a couple of conversion functions - if you've got the data as text, they'll convert each way...
using System;
using System.Linq;
class Test
{
static void Main()
{
string oracle = "329DD817216CD6429B989F5201288DBF";
string dotNet = "17D89D326C2142D69B989F5201288DBF";
Console.WriteLine(oracle == DotNetToOracle(dotNet));
Console.WriteLine(dotNet == OracleToDotNet(oracle));
}
static string OracleToDotNet(string text)
{
byte[] bytes = ParseHex(text);
Guid guid = new Guid(bytes);
return guid.ToString("N").ToUpperInvariant();
}
static string DotNetToOracle(string text)
{
Guid guid = new Guid(text);
return BitConverter.ToString(guid.ToByteArray()).Replace("-", "");
}
static byte[] ParseHex(string text)
{
// Not the most efficient code in the world, but
// it works...
byte[] ret = new byte[text.Length / 2];
for (int i = 0; i < ret.Length; i++)
{
ret[i] = Convert.ToByte(text.Substring(i * 2, 2), 16);
}
return ret;
}
}
Just use always your standard GUID
in .NET...
When you want to insert some GUID
into Oracle you just call Guid.ToString ( "N")
and feed that string to Oracle (in this example the param name is MyNETVAL
):
INSERT INTO MyTable ( MyRAWCol)
SELECT HEXTORAW (SUBSTR (MyNETVal, 6, 2) || SUBSTR (MyNETVal, 4, 2) || SUBSTR (MyNETVal, 2, 2) || SUBSTR (MyNETVal, 0, 2) || SUBSTR (MyNETVal, 10, 2) || SUBSTR (MyNETVal, 8, 2) || SUBSTR (MyNETVal, 14, 2) || SUBSTR (MyNETVal, 12, 2) || SUBSTR (MyNETVal, 16, 16)) FROM DUAL;
When you read a RAW
from Oracle you use:
SELECT
SUBSTR (HexV, 6, 2) || SUBSTR (HexV, 4, 2) || SUBSTR (HexV, 2, 2) || SUBSTR (HexV, 0, 2) || SUBSTR (HexV, 10, 2) || SUBSTR (HexV, 8, 2) || SUBSTR (HexV, 14, 2) || SUBSTR (HexV, 12, 2) || SUBSTR (HexV, 16, 16) AS MyNETVal
FROM (SELECT RAWTOHEX (MyRAWCol) HexV FROM MyTable);
Then you can feed the returned MyNETVal
into new Guid (MyNETVal)
.
This way your code always deals with the .NET format and the byte switching occurs in the Oracle-DB... you don't polute your code with conversion code and can keep the code code the same when switchig to other DBs - just change the SQL and you are up and running... the SQL could get simpler with other DBs because some of them follow the GUID format of Windows...
I just had this same issue when storing and reading Guids from Oracle.
Jon's answer is correct for querying but if your app needs to store and read Guids from Oracle, use the FlipEndian function from this thread:
.NET Native GUID conversion
Byte[] rawBytesFromOracle;
Guid dotNetGuid = new Guid(rawBytesFromOracle).FlipEndian();
The flip is only required when reading back from Oracle.
When writing to Oracle use Guid.ToByteArray() as normal.
I spent TOO much time trying to get this simple task accomplished.
Steve