sql >> Databáze >  >> RDS >> Sqlserver

Jak vyřešit nemožnost přepnout chybu kódování při vkládání XML do SQL Serveru

Tato otázka je téměř duplikátem 2 dalších a překvapivě – i když tato je nejnovější – věřím, že v ní chybí nejlepší odpověď.

Duplikáty a to, co považuji za jejich nejlepší odpovědi, jsou:

  • Použití StringWriter pro serializaci XML (2009-10-14)
    • https://stackoverflow.com/a/1566154/751158
  • Pokus o uložení obsahu XML do SQL Server 2005 se nezdařil (problém s kódováním) (2008-12-21)
    • https://stackoverflow.com/a/1091209/751158

V konečném důsledku nezáleží na tom, jaké kódování je deklarováno nebo používáno, pokud XmlReader může jej analyzovat lokálně v rámci aplikačního serveru.

Jak bylo potvrzeno v Nejefektivnější způsob čtení XML v ADO.net ze sloupce typu XML na SQL serveru?, SQL Server ukládá XML v efektivním binárním formátu. Pomocí SqlXml třídy, může ADO.net komunikovat se serverem SQL Server v tomto binárním formátu a nevyžaduje, aby databázový server prováděl jakoukoli serializaci nebo de-serializaci XML. To by mělo být také efektivnější pro přenos po síti.

Pomocí SqlXml , XML bude odesláno předem analyzované do databáze a DB pak nemusí vědět nic o kódování znaků - UTF-16 nebo jinak. Zejména si uvědomte, že deklarace XML nejsou ani perzistentní s daty v databázi, bez ohledu na to, jaká metoda je použita k jejich vložení.

Metody, které vypadají velmi podobně, najdete ve výše uvedených odpovědích, ale tento příklad je 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();
            }
        }
    }
}

Všimněte si, že poslední (nekomentovaný) příklad bych nepovažoval za "produkčně připravený", ale nechal jsem jej tak, aby byl stručný a čtivý. Pokud se to udělá správně, oba StringReader a vytvořený XmlReader by měl být inicializován v rámci using příkazy, abyste zajistili, že jejich Close() metody jsou volány po dokončení.

Z toho, co jsem viděl, nejsou deklarace XML při použití sloupce XML nikdy zachovány. I bez použití .NET a pouze pomocí tohoto přímého SQL příkazu vložení se například XML deklarace neuloží do databáze s XML:

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

Nyní, pokud jde o otázku OP, objekt, který má být serializován, je stále třeba převést na strukturu XML z MyMessage objekt a XmlSerializer je k tomu stále potřeba. V nejhorším případě by však místo serializace do řetězce mohla být zpráva místo toho serializována do XmlDocument - který pak může být předán SqlXml prostřednictvím nového XmlNodeReader - zamezení de-serializačního/serializačního výletu do řetězce. (Podrobnosti a příklad najdete na http://blogs.msdn.com/b/jongallant/archive/2007/01/30/how-to-convert-xmldocument-to-xmlreader-for-sqlxml-data-type.aspx .)

Vše zde bylo vyvinuto a testováno s .NET 4.0 a SQL Server 2008 R2.

Nedělejte prosím odpad spuštěním XML prostřednictvím zvláštních konverzí (de-deserializace a serializace – na DOM, řetězce nebo jinak), jak je uvedeno v jiných odpovědích zde i jinde.



  1. oracle 11g a integrace hibernate spring a jsf

  2. Je možné provést více aktualizací jedním příkazem UPDATE SQL?

  3. Nelze vrátit výsledky z uložené procedury pomocí kurzoru Pythonu

  4. Jak pivotovat neznámý počet sloupců a žádný agregát na SQL Server?