Как сохранить байты UTF-8 из строки C# в столбце TEXT SQL Server 2000

У меня есть база данных SQL Server 2000, которая хранит текстовые представления UTF-8 в столбце TEXT. У меня нет возможности изменить тип столбца, и я должен быть в состоянии сохранить данные Unicode, отличные от ASCII, из программы на C# в этот столбец.

Вот код:

sqlcmd.CommandText =
    "INSERT INTO Notes " +
    "(UserID, LocationID, Note) " +
    "VALUES (" +
        Note.UserId.ToString() + ", " +
        Note.LocationID.ToString() + ", " +
        "@note); " +
    "SELECT CAST(SCOPE_IDENTITY() AS BIGINT) ";

SqlParameter noteparam = new SqlParameter( "@note", System.Data.SqlDbType.Text, int.MaxValue );

На данный момент я попробовал несколько разных способов получить мои данные UTF-8 в параметр. Например:

// METHOD ONE
byte[] bytes = (byte[]) Encoding.UTF8.GetBytes( Note.Note );
char[] characters = bytes.Select( b => (char) b ).ToArray();
noteparam.Value = new String( characters );

Я также попробовал просто

// METHOD TWO
noteparam.Value = Note.Note;

А также

// METHOD THREE
byte[] bytes = (byte[]) Encoding.UTF8.GetBytes( Note.Note );
noteparam.Value = bytes;

Продолжая, вот остаток кода:

sqlcmd.Parameters.Add( noteparam );
sqlcmd.Prepare();

try
    {
    Note.RecordId = (Int64) sqlcmd.ExecuteScalar();
    }
catch
    {
    return false;
    }

Первый метод (получение байтов UTF8 в строку) делает что-то странное - я думаю, что это UTF-8, кодирующий строку во второй раз.

Метод два магазина мусора.

Метод три вызывает исключение в ExecuteScalar(), утверждая, что он не может преобразовать параметр в строку.

Вещи, которые я уже знаю, поэтому нет необходимости рассказывать мне:

  • SQL Server 2000 окончен / приближается к концу
  • Столбцы TEXT не предназначены для текста Unicode
  • Серьезно, SQL Server 2000 старый. Вам нужно обновить.

Какие-либо предложения?

1 ответ

Решение

Если ваша база данных сортировки SQL_Latin1_General_CP1 (по умолчанию для США выпуск SQL Server 2000), то вы можете использовать следующий трюк для хранения текста Unicode как UTF-8 в char, varchar, или же text колонка:

byte[] bytes = Encoding.UTF8.GetBytes(Note.Note);
noteparam.Value = Encoding.GetEncoding(1252).GetString(bytes);

Позже, когда вы захотите прочитать текст обратно, выполните обратный процесс:

SqlDataReader reader;
// ...
byte[] bytes = Encoding.GetEncoding(1252).GetBytes((string)reader["Note"]);
string note = Encoding.UTF8.GetString(bytes);

Если ваша база данных не SQL_Latin1_General_CP1, вам нужно заменить 1252 на правильную кодовую страницу.

Примечание. Если вы посмотрите на сохраненный текст в Enterprise Manager или Query Analyzer, вы увидите странные символы вместо текста, отличного от ASCII, как если бы вы открывали документ UTF-8 в текстовом редакторе, который не поддерживает Unicode.,

Как это работает: при сохранении текста Unicode в столбце, отличном от Unicode, SQL Server автоматически преобразует текст из Unicode в кодовую страницу, указанную в сопоставлении базы данных. Любые символы Юникода, которых нет на целевой кодовой странице, будут необратимо искажены, поэтому первые два метода не сработали.

Но вы были на правильном пути с методом один. Недостающим шагом является "защита" необработанных байтов UTF-8 путем преобразования их в Unicode с использованием кодовой страницы Windows-1252. Теперь, когда SQL Server выполняет автоматическое преобразование из Unicode в Windows-1252, он возвращает исходные байты UTF-8 без изменений.

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