`MySqlDataReader.GetGuid` возвращает неправильный UUID

Я генерирую UUID, используя UUID_TO_BIN(UUID(), true), и сохраняю их как BINARY(16).

Однако при получении значений:

var uuid = dataReader.GetGuid(name);
Console.WriteLine(uuid.ToString());

Я печатаю строку uuid, но это не та же строка, что и при запуске SELECT BIN_TO_UUID("col") в столбце.

Что я делаю не так?

  • Я попытался установить OldGuids в строке подключения на true, но все равно получил тот же неверный uuid.
  • Я использую MySql.Data .NET Connector версии 8.3.0. И сервер версии 8.0.36.
  • Причина, по которой я использую UUID_TO_BIN(UUID(), true) и сохраняю их как BINARY(16), заключается в том, что, согласно моим показаниям, я считаю, что это наиболее эффективный способ хранения uuid и использования их в качестве первичных ключей.

Спасибо

Дополнительная информация

Операция Возврат GetGuid(col) 3da4ec11-3568-cfb4-92aa-b42e99eb957f BIN_TO_UUID(col) 11eca43d-6835-b4cf-92aa-b42e99eb957f BIN_TO_UUID(col, true) 6835b4cf-a43d-11ec-92aa-b42e99eb957f

Если вы конвертируете значение на входе, я ожидаю, что вам придется конвертировать его на выходе. Но я ничего не знаю о MySQL и uuids.

Jeremy Lakeman 20.05.2024 07:09

в чем разница между этими двумя руководствами? Можете ли вы разделить ценности, которые, по вашему мнению, должны быть одинаковыми? Кроме того: BIN_TO_UUID("col") не является обратным тому, как вы сгенерировали UUID, но это может быть упущением.

rene 20.05.2024 08:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам нужно вручную исправить проблему с порядком байтов следующим образом:

var v = dataReader.GetValue(dataReader.GetOrdinal(name));
if (v is byte[] data && data.Length == 16)
    return new Guid(data, bigEndian: true);

Причина этого в том, что MySQL создает строку GUID в побайтовом порядке, а .NET преобразует первые три раздела в целочисленную форму с порядком байтов по умолчанию. MySqlDataReader.GetGuid по умолчанию не меняет порядок байтов, поэтому в целом это будет LE.

Это отличный ответ, но для его использования ОП придется переключиться с MySql.Data на MySqlConnector.

Bradley Grainger 20.05.2024 15:07

Спасибо, что указали на мою ошибку. Однако ключевая проблема связана с разным порядком байтов при чтении на двух языках, независимо от второго параметра. Предполагая, что двоичный идентификатор равен 0x010203040506..., BIN_TO_UUID выведет его как 01020304-0506..., а .net по умолчанию будет читать его с прямым порядком байтов как 0x04030201, 0x0605, ...

shingo 20.05.2024 16:30
Ответ принят как подходящий

Если вы создаете и сохраняете их с помощью UUID_TO_BIN(UUID(), true), вам нужно будет прочитать их обратно с помощью BIN_TO_UUID(columnName, true).

MySqlDataReader.GetGuid в MySQL Connector/NET (т. е. MySql.Data) не имеет возможности сделать это. Вот некоторые варианты:

  1. Измените свой SQL, чтобы использовать BIN_TO_UUID(columnName, true) везде, удалите Old Guids=true из строки подключения и используйте GetGuid для чтения возвращаемой строки.
  2. Прекратите использовать флаг true при использовании UUID_TO_BIN для хранения GUID (и просто используйте UUID_TO_BIN(UUID())); это расположит байты в том порядке, который ожидает GetGuid.
  3. Переключитесь на MySqlConnector и используйте GuidFormat = TimeSwapBinary16 в строке подключения.

О, я не знал, что мне нужно преобразовать его обратно, используя флаг true! Используя (1), читая столбец как BIN_TO_UUID(columnName, true) и используя GetGuid, возвращаемый Guid получает правильное значение, например, такое же, как SELECT BIN_TO_UUID(columnName, true). Но тогда я мог бы просто использовать GetString, чтобы прочитать это. При использовании варианта (2) будет ли GetGuid читаться двоичные данные напрямую?

Karmeye 24.05.2024 06:21

Причина, по которой я использовал флаг true, заключается в том, что где-то в документации MySql я читал, что он более производительный (с использованием MAC-адреса сервера). Но я не знаю, применимо ли это сейчас, и правильно ли я вообще понял документацию. Я предпочитаю просто использовать UUID_TO_BIN(UUID()), если это так эффективно. Но база данных уже используется уже пару лет, поэтому я не думаю, что смогу сейчас изменить uuid.

Karmeye 24.05.2024 06:31
UUID_TO_BIN(x, true) может повысить производительность, если столбец проиндексирован, благодаря способу хранения значений, основанных на времени. В противном случае в этом нет необходимости. Однако, как только вы начнете использовать флаг , true, вам следует использовать его последовательно для записи и чтения GUID из этого столбца, чтобы вы гарантированно получали правильные значения.
Bradley Grainger 24.05.2024 15:56

Хорошо, хорошо, потому что эти uuid являются первичными ключами, поэтому они индексируются. Знаете ли вы, повлияет ли смена оборудования на производительность? С этого момента будет другой MAC-адрес, на котором основан uuid.

Karmeye 31.05.2024 05:05

@Karmeye MAC-адрес хранится в последних шести байтах UUID v1, поэтому имеет значение (для порядка UUID в индексе), только если два UUID v1 были сгенерированы в течение одного и того же 100-наносекундного интервала.

Bradley Grainger 31.05.2024 14:59

Ого, вы хорошо разбираетесь в этих вопросах! Правильно ли я вас понимаю, что улучшение производительности с использованием только флага true относится к последовательной генерации uuid? Итак, при запросе к базе данных, например, с помощью SELECT, используется ли флаг true или нет, не влияет на производительность?

Karmeye 02.06.2024 04:43

@Karmeye Это правильно. Флаг true используется для изменения GUID, чтобы они с большей вероятностью были добавлены в виде новых строк в конце таблицы, а не вставлены в середину таблицы, что приведет к перемещению существующих данных. . Использование флага true или его отсутствие не влияет на производительность поиска существующих данных.

Bradley Grainger 02.06.2024 22:17

Производительность поиска была единственной причиной, по которой я добавил этот флаг. Мне следовало сначала спросить здесь :) Возможно, в какой-то момент я конвертирую все uuid. Спасибо!

Karmeye 08.06.2024 08:43

Другие вопросы по теме

Похожие вопросы