sql >> Databasteknik >  >> RDS >> Sqlserver

Hur man löser oförmögen att byta kodningsfel när XML infogas i SQL Server

Den här frågan är nästan en dubblett av två andra, och överraskande nog - även om den här är den senaste - tror jag att den saknar det bästa svaret.

Dubletterna, och vad jag tror är deras bästa svar, är:

  • Använda StringWriter för XML-serialisering (2009-10-14)
    • https://stackoverflow.com/a/1566154/751158
  • Försöker att lagra XML-innehåll i SQL Server 2005 misslyckas (kodningsproblem) (2008-12-21)
    • https://stackoverflow.com/a/1091209/751158

I slutändan spelar det ingen roll vilken kodning som deklareras eller används, så länge som XmlReader kan analysera det lokalt inom applikationsservern.

Som bekräftades i Det effektivaste sättet att läsa XML i ADO.net från XML-typkolumnen i SQL-servern?, lagrar SQL Server XML i ett effektivt binärt format. Genom att använda SqlXml klass, ADO.net kan kommunicera med SQL Server i detta binära format, och kräver inte att databasservern gör någon serialisering eller avserialisering av XML. Detta borde också vara mer effektivt för transport över nätverket.

Genom att använda SqlXml , kommer XML att skickas förtolkat till databasen, och då behöver DB:n inte veta något om teckenkodningar - UTF-16 eller annat. Observera särskilt att XML-deklarationerna inte ens finns kvar med data i databasen, oavsett vilken metod som används för att infoga den.

Se de ovan länkade svaren för metoder som liknar detta, men det här exemplet är mitt:

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

Observera att jag inte skulle anse det sista (icke-kommenterade) exemplet som "produktionsfärdigt", utan lämnade det som det är för att vara kortfattat och läsbart. Om det görs korrekt, både StringReader och den skapade XmlReader bör initieras inom using satser för att säkerställa att deras Close() metoder anropas när de är klara.

Vad jag har sett är XML-deklarationerna aldrig kvar när man använder en XML-kolumn. Även utan att använda .NET och bara använda denna direkta SQL insert-sats, till exempel, sparas inte XML-deklarationen i databasen med XML:

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

Nu när det gäller OP:s fråga, måste objektet som ska serialiseras fortfarande konverteras till en XML-struktur från MyMessage objekt och XmlSerializer behövs fortfarande för detta. Men i värsta fall, istället för att serialiseras till en sträng, kan meddelandet istället serialiseras till ett XmlDocument - som sedan kan skickas till SqlXml genom en ny XmlNodeReader - undvika en avserialisering/serialiseringsresa till en sträng. (Se http://blogs.msdn.com/b/jongallant/archive/2007/01/30/how-to-convert-xmldocument-to-xmlreader-for-sqlxml-data-type.aspx för detaljer och ett exempel .)

Allt här har utvecklats mot och testats med .NET 4.0 och SQL Server 2008 R2.

Snälla gör inte avfall genom att köra XML genom extra omvandlingar (avserialiseringar och serialiseringar - till DOM, strängar eller annat), som visas i andra svar här och på andra ställen.



  1. C# Motsvarar SQL Server DataTypes

  2. Jämför Amazon RDS Point-in-Time Recovery med ClusterControl

  3. PostgreSQL FÖRKLARA – Vilka är frågekostnaderna?

  4. SQL (ORACLE):ORDER BY och LIMIT