Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Jak rozwiązać problem z niemożliwością przełączenia błędu kodowania podczas wstawiania XML do SQL Server

To pytanie jest prawie duplikatem 2 innych i co zaskakujące – chociaż to jest najnowsze – uważam, że brakuje mu najlepszej odpowiedzi.

Duplikaty i to, co uważam za ich najlepsze odpowiedzi, to:

  • Używanie StringWriter do serializacji XML (2009-10-14)
    • https://stackoverflow.com/a/1566154/751158
  • Próba przechowywania zawartości XML w SQL Server 2005 kończy się niepowodzeniem (problem z kodowaniem) (2008-12-21)
    • https://stackoverflow.com/a/1091209/751158

W końcu nie ma znaczenia, jakie kodowanie jest zadeklarowane lub użyte, o ile XmlReader może analizować je lokalnie na serwerze aplikacji.

Jak zostało potwierdzone w Najbardziej efektywny sposób odczytywania XML w ADO.net z kolumny typu XML w serwerze SQL?, SQL Server przechowuje XML w wydajnym formacie binarnym. Używając SqlXml klasy, ADO.net może komunikować się z SQL Server w tym formacie binarnym i nie wymaga od serwera bazy danych wykonywania jakiejkolwiek serializacji lub deserializacji XML. Powinno to być również bardziej wydajne w przypadku transportu w sieci.

Używając SqlXml , XML zostanie przesłany do bazy danych wstępnie przeanalizowany, a następnie DB nie musi nic wiedzieć o kodowaniu znaków - UTF-16 lub innym. W szczególności zauważ, że deklaracje XML nie są nawet utrwalane z danymi w bazie danych, niezależnie od metody użytej do ich wstawienia.

Proszę odnieść się do powyższych odpowiedzi dla metod, które wyglądają bardzo podobnie do tego, ale ten przykład jest mój:

using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using System.Xml;

static class XmlDemo {
    static void Main(string[] args) {
        using(SqlConnection conn = new SqlConnection()) {
            conn.ConnectionString = "...";
            conn.Open();

            using(SqlCommand cmd = new SqlCommand("Insert Into TestData(Xml) Values (@Xml)", conn)) {

                cmd.Parameters.Add(new SqlParameter("@Xml", SqlDbType.Xml) {
                    // Works.
                    // Value = "<Test/>"

                    // Works.  XML Declaration is not persisted!
                    // Value = "<?xml version=\"1.0\"?><Test/>"

                    // Works.  XML Declaration is not persisted!
                    // Value = "<?xml version=\"1.0\" encoding=\"UTF-16\"?><Test/>"

                    // Error ("unable to switch the encoding" SqlException).
                    // Value = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Test/>"

                    // Works.  XML Declaration is not persisted!
                    Value = new SqlXml(XmlReader.Create(new StringReader("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Test/>")))
                });

                cmd.ExecuteNonQuery();
            }
        }
    }
}

Zauważ, że nie uważam ostatniego (nie komentowanego) przykładu za „gotowy do produkcji”, ale zostawiłem go tak, aby był zwięzły i czytelny. Jeśli zrobisz to poprawnie, oba StringReader i utworzony XmlReader powinien być zainicjowany w using instrukcji, aby upewnić się, że ich Close() metody są wywoływane po zakończeniu.

Z tego, co widziałem, deklaracje XML nigdy nie są utrwalane podczas korzystania z kolumny XML. Nawet bez użycia .NET i tylko przy użyciu tej bezpośredniej instrukcji wstawiania SQL, na przykład, deklaracja XML nie jest zapisywana w bazie danych z XML:

Insert Into TestData(Xml) Values ('<?xml version="1.0" encoding="UTF-8"?><Test/>');

Teraz, jeśli chodzi o pytanie OP, obiekt do serializacji nadal musi zostać przekonwertowany na strukturę XML z MyMessage obiekt i XmlSerializer jest do tego jeszcze potrzebny. Jednak w najgorszym przypadku zamiast serializacji do ciągu, wiadomość może zamiast tego zostać zserializowana do XmlDocument - który można następnie przekazać do SqlXml przez nowy XmlNodeReader - unikanie podróży deserializacji/serializacji do ciągu. (Zobacz http://blogs.msdn.com/b/jongallant/archive/2007/01/30/how-to-convert-xmldocument-to-xmlreader-for-sqlxml-data-type.aspx , aby uzyskać szczegółowe informacje i przykład .)

Wszystko tutaj zostało opracowane i przetestowane z .NET 4.0 i SQL Server 2008 R2.

Proszę nie marnować uruchamiając XML poprzez dodatkowe konwersje (de-deserializacje i serializacje - do DOM, stringów lub w inny sposób), jak pokazano w innych odpowiedziach tutaj i gdzie indziej.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jakie są główne różnice w wydajności między typami danych varchar i nvarchar SQL Server?

  2. Wypróbuj te sprawdzone metody monitorowania bazy danych MySQL

  3. SQL Server 2016:Utwórz kopię zapasową bazy danych

  4. Uzyskaj wiele wartości w kursorze SQL Server

  5. Dynamiczny SQL (przekazywanie nazwy tabeli jako parametru)