Как сохранить байты 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 без изменений.