Преобразование из Oracle RAW (16) в .NET GUID
У меня возникли трудности с ручной отладкой приложения .NET, где значения Guid отличаются от .NET до Oracle.
- Где С# читает:
-
17D89D326C2142D69B989F5201288DBF
- Oracle читает:
-
329DD817216CD6429B989F5201288DBF
Как я могу вручную отлаживать, т.е. из идентификатора GUID С#, можно вставить это значение в запрос оракула и получить правильные результаты (и наоборот)?
Ответы
Ответ 1
Если вы посмотрите на значения (в парах) шестнадцатеричных цифр, вы увидите, что последние 7 байтов одинаковы в обоих случаях, но первые 9 переключаются немного.
Исходя из вашего примера, но переписывая каждую пару в .NET как 00, 11, 22 и т.д. и переключая соответствующий байт Oracle, мы получаем:
Таким образом, довольно легко написать код для переключения вокруг байтов. (Я уверен, что на самом деле я написал код для этого в предыдущей работе.)
Чтобы переключить байты, вы просто хотите вызвать Guid.ToByteArray()
и new Guid(byte[])
, чтобы вернуться к Guid
.
РЕДАКТИРОВАТЬ: Как это бывает, кругооборот выше - это именно то, что делает конструктор Guid
, когда вы передаете ему массив байтов:
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("-", ""));
}
}
Печать
00112233445566778899AABBCCDDEEFF
33221100554477668899aabbccddeeff
Возможно, это значительно упростит выполнение переключения... как вам удалось получить значения для начала? Это просто "как они отображаются в Oracle"?
EDIT: Хорошо, вот пара функций преобразования - если у вас есть данные как текст, они преобразуют каждый способ...
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;
}
}
Ответ 2
У меня была такая же проблема при хранении и чтении гидов из Oracle.
Ответ Jon корректен для запросов, но если ваше приложение должно хранить и читать Guids from Oracle, используйте функцию FlipEndian из этого потока:
Преобразование .NET для собственного GUID
Byte[] rawBytesFromOracle;
Guid dotNetGuid = new Guid(rawBytesFromOracle).FlipEndian();
Флип требуется только при чтении из Oracle.
При написании в Oracle используйте Guid.ToByteArray() как обычно.
Я потратил много времени, пытаясь выполнить эту простую задачу.
Стив
Ответ 3
Если вам нужно преобразовать GUID в RAW из PL/SQL, можно использовать эту функцию:
/*
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;
Ответ 4
Просто используйте свой стандартный GUID
в .NET...
Если вы хотите вставить некоторые GUID
в Oracle, вы просто вызываете Guid.ToString ( "N")
и передаете эту строку в Oracle (в этом примере имя параметра 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;
Когда вы читаете RAW
из Oracle, вы используете:
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);
Затем вы можете вернуть возвращенный MyNETVAL
в new Guid (MyNETVal)
.
Таким образом, ваш код всегда имеет дело с форматом .NET, а переключение байтов происходит в Oracle-DB... вы не используете свой код с кодом преобразования и можете сохранить код кода одинаковым при переключении на другие БД - просто измените SQL, и вы работаете и работаете... SQL может упроститься с другими БД, потому что некоторые из них следуют GUID-формату Windows...