Как разобрать Uuid, хранящийся как char (16)? - PullRequest
1 голос
/ 20 апреля 2011

У меня есть база данных Firebird, которая хранит значения Uuid в поле char (16).В моей программе на C # мне нужно получить эти значения, чтобы использовать их в последующих запросах.Но значения, которые я получаю из базы данных, являются «мусором».(например, ¿­ñ)êNµmÏc—ÝX) Я пробовал различные методы чтения данных в виде байтового массива и использования их для создания локального Guid, но это никуда меня не привело.Самым близким, что я получил, было использование Encoding.ASCII.GetBytes(), которое дало мне «действительный» guid, однако он не соответствует «реальным» guid в базе данных.Я знаю, что они не совпадают, потому что (1) база данных имеет UDF, который преобразует «мусор» в удобочитаемую строку, и (2) когда я вручную копирую этот удобочитаемый guid в свое приложение, используя его для создания нового локальногоGuid и, используя значение THAT в своих запросах, я получаю правильные результаты.(В то время как направляющие, созданные из байтовых массивов, не дают правильных результатов.) Я также попытался IDataRecord.GetBytes(), но это привело к InvalidCastException ("Невозможно привести объект типа 'System.String' к типу 'System.Byte []'.")

Это приложение использует базы данных, созданные другим, не связанным продуктом, и я не могу контролировать его структуру, а также не могу использовать такие вещи, как хранимые процедуры.Я также не могу использовать UDF, которые я упоминал ранее, потому что они скоро прощаются.Доступные UDF, очевидно, являются простыми обертками вокруг UuidToString и UuidFromString .Я полагаю, что я мог бы использовать эти функции в своем собственном коде, но я бы предпочел, если бы не было другого способа, не связанного с взаимодействием.

В конечном счете, мне нужен гид для работыв методе, который выглядит примерно так:

protected DataTable QueryDataTable(string query, string paramName, Guid guid)
{
    DataTable table = new DataTable();
    IDbCommand command = CreateDbCommand(query);
    if (command is FbCommand)
    {
        FbCommand fbCommand = (FbCommand)command;
        fbCommand.Parameters.Add(paramName, FbDbType.Binary).Value = 
            guid.ToByteArray();

        // Also tried passing in the byte[] generated by 
        // Encoding.Ascii.GetBytes.... didn't work.
        //fbCommand.Parameters.Add(paramName, FbDbType.Binary).Value = guid;

        FbDataAdapter adapter = new FbDataAdapter(fbCommand);
        adapter.Fill(table);
    }

    return table;
}

Вопросы:

(1) Почему я не использую байтовый массив для создания guid, что приводит к «правильному»guid?

(2) Какую другую тактику я мог бы использовать, чтобы извлечь эти направляющие и сохранить их локально как таковые?

Спасибо!

Редактировать:

Вот пример того, что я имею перед собой.Из базы данных:

enter image description here

Результирующий массив символов из строки мусора:

enter image description here

Использование тактики, предложенной @Alexei Levenkovрезультирующий указатель (1) очень близок, но не совсем корректен (2).

(1): fca3120b-511e-4269-b88f-d053a34b3513
(2): fca3120b-5184-4269-b88f-d053a34b3596

НЕКОТОРЫЕ строки мусораполучается правильно, но это пример того, который не делает.Вот как я реализую предложение Алексея, так как я не видел метод Select для строк:

// table is a DataTable
List<byte> bytes = new List<byte>();
string blah = (string)table.Rows[0][0];
foreach (char c in blah.ToCharArray())
{
    bytes.Add((byte)c);
}

Guid guid = new Guid(bytes.ToArray());

Ответы [ 4 ]

3 голосов
/ 20 апреля 2011

Char (16) выглядит как байтовое представление GUID. Попробуйте преобразовать каждый символ строки в байтовый массив и создать из него GUID

new Guid("0000000000000000".Select(c=> (byte)c).ToArray())

Для обратного преобразования используйте guid.ToByteArray () и конвертируйте его в строку с кодировкой ASCII.

Encoding.ASCII.GetString(Guid.Empty.ToByteArray())
2 голосов
/ 21 апреля 2011

в Firebird 2.5 у вас есть встроенная функция, чтобы это

1 голос
/ 05 июня 2013

Этот вопрос довольно старый, но у меня была похожая проблема при работе с Firebird 2.0 (без встроенного генератора UUID).

Итак, основная проблема с кодом, представленным выше, заключалась в неправильном типе параметра (двоичный).Это должен быть FbDbType.Char или FbDbType.Guid.Ниже приведен рабочий пример.

Guid newGuid = Guid.NewGuid();
Guid retrieved = Guid.Empty;
    using (FbConnection conn = new FbConnection(connectionString)) {
        conn.Open();

        using (FbCommand cmd = conn.CreateCommand()) {
        // first create the table for testing
        cmd.CommandText = "recreate table GUID_test (guid char(16) character set octets)";
        cmd.ExecuteNonQuery();
    }

    using (FbCommand cmd = conn.CreateCommand()) {
        // inserting GUID into db table  
        cmd.CommandText = "insert into GUID_test values (@guid)";

        // classic way, works good
        //cmd.Parameters.Add("@guid", FbDbType.Char, 16).Value = newGuid.ToByteArray();

        // another way, maybe better readability, but same result
        cmd.Parameters.Add("@guid", FbDbType.Guid).Value = newGuid;

        cmd.ExecuteNonQuery();
    }

    using (FbCommand cmd = conn.CreateCommand()) {
        // reading GUID back from db  
        cmd.CommandText = "select first 1 guid from GUID_test";

        retrieved = (Guid)cmd.ExecuteScalar();
    }


    using (FbCommand cmd = conn.CreateCommand()) {
        // drop the table, it has no real application
        cmd.CommandText = "drop table GUID_test";
        cmd.ExecuteNonQuery();
    }
}
MessageBox.Show(newGuid.Equals(retrieved).ToString());
0 голосов
/ 11 июня 2013

При вставке значений направляющих, передавая их в запросе как

 "INSERT INTO MyTable(GuidCol) VALUES (CHAR_TO_UUID(" + yourGuid.ToString() + "))"

при чтении, вы можете исправить неверно проанализированное значение из провайдера данных Firebird .NET, используя следующий класс:

public class FirebirdCorrectingReader : IDataReader {
    private readonly IDataReader _decoratedReader;

    public FirebirdCorrectingReader(IDataReader decoratedReader) {
        _decoratedReader = decoratedReader; 
    }

    #region DataReader Impl

    public void Dispose() {
        _decoratedReader.Dispose();
    }

    public string GetName(int i) {
        return _decoratedReader.GetName(i);
    }

    public string GetDataTypeName(int i) {
        return _decoratedReader.GetDataTypeName(i);
    }

    public Type GetFieldType(int i) {
        return _decoratedReader.GetFieldType(i);
    }

    public object GetValue(int i) {
        var result = _decoratedReader.GetValue(i);
        if (result is Guid) {
            result = CorrectGuid((Guid)result);
        }
        return result;
    }

    public int GetValues(object[] values) {
        return _decoratedReader.GetValues(values);
    }

    public int GetOrdinal(string name) {
        return _decoratedReader.GetOrdinal(name);
    }

    public bool GetBoolean(int i) {
        return _decoratedReader.GetBoolean(i);
    }

    public byte GetByte(int i) {
        return _decoratedReader.GetByte(i);
    }

    public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) {
        return _decoratedReader.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
    }

    public char GetChar(int i) {
        return _decoratedReader.GetChar(i);
    }

    public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) {
        return _decoratedReader.GetChars(i, fieldoffset, buffer, bufferoffset, length);
    }

    public Guid GetGuid(int i) {
        return CorrectGuid(_decoratedReader.GetGuid(i));
    }

    public short GetInt16(int i) {
        return _decoratedReader.GetInt16(i);
    }

    public int GetInt32(int i) {
        return _decoratedReader.GetInt32(i);
    }

    public long GetInt64(int i) {
        return _decoratedReader.GetInt64(i);
    }

    public float GetFloat(int i) {
        return _decoratedReader.GetFloat(i);
    }

    public double GetDouble(int i) {
        return _decoratedReader.GetDouble(i);
    }

    public string GetString(int i) {
        return _decoratedReader.GetString(i);
    }

    public decimal GetDecimal(int i) {
        return _decoratedReader.GetDecimal(i);
    }

    public DateTime GetDateTime(int i) {
        return _decoratedReader.GetDateTime(i);
    }

    public IDataReader GetData(int i) {
        return _decoratedReader.GetData(i);
    }

    public bool IsDBNull(int i) {
        return _decoratedReader.IsDBNull(i);
    }

    public int FieldCount { get { return _decoratedReader.FieldCount; } }

    object IDataRecord.this[int i] {
        get { return _decoratedReader[i]; }
    }

    object IDataRecord.this[string name] {
        get {return _decoratedReader[name]; }
    }

    public void Close() {
        _decoratedReader.Close();
    }

    public DataTable GetSchemaTable() {
        return _decoratedReader.GetSchemaTable();
    }

    public bool NextResult() {
        return _decoratedReader.NextResult();
    }

    public bool Read() {
        return _decoratedReader.Read();
    }

    public int Depth { get { return _decoratedReader.Depth; } }
    public bool IsClosed { get { return _decoratedReader.IsClosed; } }
    public int RecordsAffected { get { return _decoratedReader.RecordsAffected; } }

    #endregion

    public static Guid CorrectGuid(Guid badlyParsedGuid) {
        var rfc4122bytes = badlyParsedGuid.ToByteArray();
        if (BitConverter.IsLittleEndian) {
            Array.Reverse(rfc4122bytes, 0, 4);
            Array.Reverse(rfc4122bytes, 4, 2);
            Array.Reverse(rfc4122bytes, 6, 2);
        }
        return new Guid(rfc4122bytes);
    }
}

Примечание : не используйте этот класс, когда эта ошибка исправлена.

...