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.