Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Wie man den Codierungsfehler beim Einfügen von XML in SQL Server nicht wechseln kann

Diese Frage ist fast identisch mit 2 anderen, und überraschenderweise - obwohl diese die neueste ist - glaube ich, dass ihr die beste Antwort fehlt.

Die Duplikate und meiner Meinung nach die besten Antworten sind:

  • Verwenden von StringWriter für die XML-Serialisierung (2009-10-14)
    • https://stackoverflow.com/a/1566154/751158
  • Der Versuch, XML-Inhalte in SQL Server 2005 zu speichern, schlägt fehl (Codierungsproblem) (2008-12-21)
    • https://stackoverflow.com/a/1091209/751158

Letztendlich spielt es keine Rolle, welche Kodierung deklariert oder verwendet wird, solange der XmlReader kann es lokal innerhalb des Anwendungsservers parsen.

Wie in Most Efficient Way to Read XML in ADO.net from XML type Column in SQL Server? bestätigt wurde, speichert SQL Server XML in einem effizienten Binärformat. Durch die Verwendung von SqlXml -Klasse kann ADO.net in diesem Binärformat mit SQL Server kommunizieren und erfordert vom Datenbankserver keine Serialisierung oder Deserialisierung von XML. Dies sollte auch für den Transport über das Netzwerk effizienter sein.

Durch die Verwendung von SqlXml , XML wird vorparsed an die Datenbank gesendet, und die DB muss nichts über Zeichenkodierungen wissen - UTF-16 oder anderes. Beachten Sie insbesondere, dass die XML-Deklarationen nicht einmal mit den Daten in der Datenbank persistiert werden, unabhängig davon, welche Methode zum Einfügen verwendet wird.

Bitte beachten Sie die oben verlinkten Antworten für Methoden, die dieser sehr ähnlich sehen, aber dieses Beispiel ist von mir:

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();
            }
        }
    }
}

Beachten Sie, dass ich das letzte (nicht kommentierte) Beispiel nicht als "produktionsreif" betrachten würde, sondern es so belassen würde, dass es prägnant und lesbar ist. Bei richtiger Ausführung werden sowohl der StringReader und den erstellten XmlReader sollte innerhalb von using initialisiert werden Anweisungen, um sicherzustellen, dass ihre Close() Methoden werden nach Abschluss aufgerufen.

Soweit ich gesehen habe, werden die XML-Deklarationen nie beibehalten, wenn eine XML-Spalte verwendet wird. Auch ohne Verwendung von .NET und beispielsweise nur mit dieser direkten SQL-Insert-Anweisung wird die XML-Deklaration nicht mit XML:

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

In Bezug auf die Frage des OP muss das zu serialisierende Objekt noch in eine XML-Struktur aus MyMessage konvertiert werden Objekt und XmlSerializer wird dafür noch benötigt. Im schlimmsten Fall könnte die Nachricht jedoch anstelle einer Serialisierung in einen String stattdessen in ein XmlDocument serialisiert werden - die dann an SqlXml übergeben werden können durch einen neuen XmlNodeReader - Vermeiden eines Deserialisierungs-/Serialisierungstrips zu einem String. (Einzelheiten und ein Beispiel finden Sie unter http://blogs.msdn.com/b/jongallant/archive/2007/01/30/how-to-convert-xmldocument-to-xmlreader-for-sqlxml-data-type.aspx .)

Alles hier wurde gegen .NET 4.0 und SQL Server 2008 R2 entwickelt und getestet.

Bitte machen Sie keinen Abfall durch Ausführen von XML durch zusätzliche Konvertierungen (Deserialisierung und Serialisierung - in DOM, Zeichenfolgen oder auf andere Weise), wie in anderen Antworten hier und an anderer Stelle gezeigt.