sql >> Database teknologi >  >> RDS >> Sqlserver

Sådan løses ude af stand til at skifte kodningsfejlen, når du indsætter XML i SQL Server

Dette spørgsmål er næsten en dublet af 2 andre, og overraskende nok - selvom dette er det seneste - mener jeg, at det mangler det bedste svar.

Dubletterne, og hvad jeg mener er deres bedste svar, er:

  • Brug af StringWriter til XML-serialisering (2009-10-14)
    • https://stackoverflow.com/a/1566154/751158
  • Forsøg på at gemme XML-indhold i SQL Server 2005 mislykkes (kodningsproblem) (2008-12-21)
    • https://stackoverflow.com/a/1091209/751158

I sidste ende er det ligegyldigt, hvilken kodning der erklæres eller bruges, så længe XmlReader kan parse det lokalt på applikationsserveren.

Som det blev bekræftet i Mest effektive måde at læse XML i ADO.net fra XML type kolonne i SQL server?, gemmer SQL Server XML i et effektivt binært format. Ved at bruge SqlXml klasse, kan ADO.net kommunikere med SQL Server i dette binære format og ikke kræve, at databaseserveren foretager nogen serialisering eller de-serialisering af XML. Dette skulle også være mere effektivt til transport på tværs af netværket.

Ved at bruge SqlXml , vil XML blive sendt præpareret til databasen, og så behøver DB'en ikke at vide noget om tegnkodninger - UTF-16 eller andet. Bemærk især, at XML-erklæringerne ikke engang bliver ved med dataene i databasen, uanset hvilken metode der bruges til at indsætte dem.

Se venligst ovenstående linkede svar for metoder, der ligner meget dette, men dette eksempel er mit:

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

Bemærk, at jeg ikke ville anse det sidste (ikke-kommenterede) eksempel for at være "produktionsklart", men lod det være som det er for at være kortfattet og læsbart. Hvis det gøres korrekt, både StringReader og den oprettede XmlReader skal initialiseres inden for using sætninger for at sikre, at deres Close() metoder kaldes, når de er færdige.

Fra hvad jeg har set, er XML-deklarationerne aldrig vedvarende, når du bruger en XML-kolonne. Selv uden at bruge .NET og blot bruge denne direkte SQL insert-sætning, for eksempel, gemmes XML-deklarationen ikke i databasen med XML:

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

Med hensyn til OP's spørgsmål skal objektet, der skal serialiseres, stadig konverteres til en XML-struktur fra MyMessage objekt og XmlSerializer er stadig nødvendig for dette. Men i værste fald, i stedet for at serialisere til en streng, kan meddelelsen i stedet serialiseres til et XmlDocument - som derefter kan sendes til SqlXml gennem en ny XmlNodeReader - at undgå en de-serialisering/serialiseringstur til en streng. (Se http://blogs.msdn.com/b/jongallant/archive/2007/01/30/how-to-convert-xmldocument-to-xmlreader-for-sqlxml-data-type.aspx for detaljer og et eksempel .)

Alt her er udviklet mod og testet med .NET 4.0 og SQL Server 2008 R2.

Giv ikke spild ved at køre XML gennem ekstra konverteringer (de-deserialiseringer og serialiseringer - til DOM, strenge eller andet), som vist i andre svar her og andre steder.



  1. MODIFY COLUMN i oracle - Hvordan kontrollerer man, om en kolonne er nullbar, før den indstilles til nullbar?

  2. Flere planer for en identisk forespørgsel

  3. Sådan fungerer GET_FORMAT() i MariaDB

  4. Sådan tilføjer du standardbegrænsning til eksisterende kolonner i SQL Server-tabel - SQL Server / TSQL selvstudium, del 91