sql >> Database >  >> RDS >> Sqlserver

Hoe op te lossen dat de coderingsfout niet kan worden gewijzigd bij het invoegen van XML in SQL Server

Deze vraag is een bijna duplicaat van twee andere, en verrassend genoeg - hoewel deze de meest recente is - geloof ik dat het beste antwoord ontbreekt.

De duplicaten, en wat volgens mij hun beste antwoorden zijn, zijn:

  • StringWriter gebruiken voor XML-serialisatie (2009-10-14)
    • https://stackoverflow.com/a/1566154/751158
  • Proberen om XML-inhoud op te slaan in SQL Server 2005 mislukt (coderingsprobleem) (2008-12-21)
    • https://stackoverflow.com/a/1091209/751158

Uiteindelijk maakt het niet uit welke codering wordt gedeclareerd of gebruikt, zolang de XmlReader kan het lokaal ontleden binnen de applicatieserver.

Zoals werd bevestigd in De meest efficiënte manier om XML te lezen in ADO.net van de kolom XML-type in SQL server?, slaat SQL Server XML op in een efficiënt binair formaat. Door de SqlXml . te gebruiken class, kan ADO.net communiceren met SQL Server in dit binaire formaat, en hoeft de databaseserver geen serialisatie of deserialisatie van XML uit te voeren. Dit zou ook efficiënter moeten zijn voor transport over het netwerk.

Door SqlXml . te gebruiken , XML wordt vooraf geparseerd naar de database verzonden en dan hoeft de DB niets te weten over tekencoderingen - UTF-16 of anderszins. Merk in het bijzonder op dat de XML-declaraties niet eens worden bewaard bij de gegevens in de database, ongeacht de methode die wordt gebruikt om deze in te voegen.

Raadpleeg de hierboven gelinkte antwoorden voor methoden die hier erg op lijken, maar dit voorbeeld is van mij:

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

Merk op dat ik het laatste (niet-becommentarieerde) voorbeeld niet als "klaar voor productie" zou beschouwen, maar het ongewijzigd gelaten om beknopt en leesbaar te zijn. Als het goed wordt gedaan, kunnen zowel de StringReader en de gemaakte XmlReader moet worden geïnitialiseerd binnen using instructies om ervoor te zorgen dat hun Close() methoden worden aangeroepen als ze voltooid zijn.

Van wat ik heb gezien, blijven de XML-declaraties nooit behouden bij gebruik van een XML-kolom. Zelfs zonder .NET te gebruiken en alleen deze directe SQL-insert-instructie te gebruiken, wordt de XML-declaratie niet opgeslagen in de database met de XML:

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

Nu, in termen van de OP's vraag, het te serialiseren object moet nog worden geconverteerd naar een XML-structuur uit de MyMessage object, en XmlSerializer is hiervoor nog nodig. In het slechtste geval kan het bericht echter worden geserialiseerd naar een XmlDocument in plaats van te serialiseren naar een string. - die vervolgens kan worden doorgegeven aan SqlXml via een nieuwe XmlNodeReader - het vermijden van een de-serialisatie/serialisatie-trip naar een string. (Zie http://blogs.msdn.com/b/jongallant/archive/2007/01/30/how-to-convert-xmldocument-to-xmlreader-for-sqlxml-data-type.aspx voor details en een voorbeeld .)

Alles hier is ontwikkeld tegen en getest met .NET 4.0 en SQL Server 2008 R2.

Verspil alsjeblieft geen verspilling door XML door extra conversies te laten lopen (deserialisaties en serialisaties - naar DOM, strings of anderszins), zoals getoond in andere antwoorden hier en elders.



  1. LN() Functie in Oracle

  2. 3 manieren om rijen te vinden die hoofdletters bevatten in SQLite

  3. Een overzicht van PostgreSQL-querycaching en taakverdeling

  4. Maak een database-e-mailaccount in SQL Server (T-SQL)