Ich suche derzeit nach einer einfachen Möglichkeit, Objekte zu serialisieren (in C # 3).
Ich habe einige Beispiele gegoogelt und mir etwas ausgedacht wie:
MemoryStream memoryStream = new MemoryStream ( );
XmlSerializer xs = new XmlSerializer ( typeof ( MyObject) );
XmlTextWriter xmlTextWriter = new XmlTextWriter ( memoryStream, Encoding.UTF8 );
xs.Serialize ( xmlTextWriter, myObject);
string result = Encoding.UTF8.GetString(memoryStream .ToArray());
Nachdem ich diese Frage gelesen hatte , fragte ich mich, warum ich nicht StringWriter benutze. Es scheint viel einfacher.
XmlSerializer ser = new XmlSerializer(typeof(MyObject));
StringWriter writer = new StringWriter();
ser.Serialize(writer, myObject);
serializedValue = writer.ToString();
Ein weiteres Problem war, dass das erste Beispiel XML generierte, das ich nicht einfach in eine XML-Spalte der SQL Server 2005-Datenbank schreiben konnte.
Die erste Frage lautet: Gibt es einen Grund, warum ich StringWriter nicht zum Serialisieren eines Objekts verwenden sollte, wenn ich es anschließend als Zeichenfolge benötige? Ich habe beim Googeln mit StringWriter nie ein Ergebnis gefunden.
Das zweite ist natürlich: Wenn Sie es nicht mit StringWriter machen sollten (aus welchen Gründen auch immer), was wäre ein guter und korrekter Weg?
Zusatz:
Wie bereits in beiden Antworten erwähnt, werde ich weiter auf das XML-zu-DB-Problem eingehen.
Beim Schreiben in die Datenbank habe ich folgende Ausnahme erhalten:
System.Data.SqlClient.SqlException: XML-Analyse: Zeile 1, Zeichen 38, Codierung kann nicht geändert werden
Für String
<?xml version="1.0" encoding="utf-8"?><test/>
Ich habe die aus dem XmlTextWriter erstellte Zeichenfolge genommen und dort einfach als XML eingefügt. Dieser funktionierte nicht (auch nicht beim manuellen Einfügen in die DB).
Danach habe ich versucht, manuell einzufügen (nur INSERT INTO schreiben ...) mit encoding = "utf-16", was ebenfalls fehlgeschlagen ist. Das Entfernen der Codierung hat dann völlig funktioniert. Nach diesem Ergebnis wechselte ich zurück zum StringWriter-Code und voila - es hat funktioniert.
Problem: Ich verstehe nicht wirklich warum.
bei Christian Hayter: Bei diesen Tests bin ich mir nicht sicher, ob ich utf-16 verwenden muss, um in die DB zu schreiben. Würde es dann nicht funktionieren, die Codierung auf UTF-16 (im XML-Tag) zu setzen?
quelle
Antworten:
<TL; DR> Das Problem ist eigentlich recht einfach: Sie stimmen die deklarierte Codierung (in der XML-Deklaration) nicht mit dem Datentyp des Eingabeparameters ab. Wenn Sie
<?xml version="1.0" encoding="utf-8"?><test/>
die Zeichenfolge manuell hinzugefügt haben und dann deklarierenSqlParameter
, dass sie vom Typ ist,SqlDbType.Xml
oderSqlDbType.NVarChar
wenn der Fehler "Codierung kann nicht geändert werden" angezeigt wird. Wenn Sie dann manuell über T-SQL einfügen, haben Sie, da Sie die deklarierte Codierung auf "Umgestellt" geändert habenutf-16
, eindeutig eineVARCHAR
Zeichenfolge eingefügt (ohne ein "N" in Großbuchstaben, daher eine 8-Bit-Codierung wie UTF-8). und nicht einNVARCHAR
Zeichenfolge (mit einem vorangestellten "N" in Großbuchstaben, daher die 16-Bit-UTF-16-LE-Codierung).Das Update sollte so einfach sein wie:
encoding="utf-8"
: Fügen Sie einfach nicht die XML-Deklaration hinzu.encoding="utf-16"
:SqlDbType.NVarChar
anstelle vonSqlDbType.VarChar
:-) (oder wechseln Sie möglicherweise sogar zu "Verwenden"SqlDbType.Xml
)(Detaillierte Antwort ist unten)
Alle Antworten hier sind zu kompliziert und unnötig (unabhängig von den 121 und 184 Up-Votes für Christians bzw. Jons Antworten). Sie stellen möglicherweise Arbeitscode bereit, aber keiner von ihnen beantwortet die Frage tatsächlich. Das Problem ist, dass niemand die Frage wirklich verstanden hat, die letztendlich die Funktionsweise des XML-Datentyps in SQL Server betrifft. Nichts gegen diese beiden eindeutig intelligenten Leute, aber diese Frage hat wenig bis gar nichts mit der Serialisierung in XML zu tun. Das Speichern von XML-Daten in SQL Server ist viel einfacher als hier impliziert.
Es spielt keine Rolle, wie das XML erstellt wird, solange Sie die Regeln zum Erstellen von XML-Daten in SQL Server befolgen. Ich habe eine ausführlichere Erklärung (einschließlich eines funktionierenden Beispielcodes zur Veranschaulichung der unten aufgeführten Punkte) in einer Antwort auf diese Frage: So lösen Sie den Fehler "Die Codierung kann nicht umgeschaltet werden" beim Einfügen von XML in SQL Server , aber die Grundlagen sind:
NVARCHAR(MAX)
oderXML
/SqlDbType.NVarChar
(maxsize = -1) oderSqlDbType.Xml
, oder wenn Sie ein Zeichenfolgenliteral verwenden, muss ein Großbuchstabe "N" vorangestellt werden.VARCHAR(MAX)
/SqlDbType.VarChar
(maxsize = -1) übergeben. Wenn Sie ein Zeichenfolgenliteral verwenden, darf diesem kein Großbuchstaben "N" vorangestellt werden.Unter Berücksichtigung der oben genannten Punkte und angesichts der Tatsache, dass Zeichenfolgen in .NET immer UTF-16 LE / UCS-2 LE sind (es gibt keinen Unterschied zwischen diesen in Bezug auf die Codierung), können wir Ihre Fragen beantworten:
Nein, Ihr
StringWriter
Code scheint in Ordnung zu sein (zumindest sehe ich keine Probleme bei meinen eingeschränkten Tests mit dem 2. Codeblock aus der Frage).Die XML-Deklaration muss nicht angegeben werden. Wenn es fehlt, wird angenommen, dass die Codierung UTF-16 LE ist, wenn Sie die Zeichenfolge als
NVARCHAR
(dhSqlDbType.NVarChar
) oderXML
(dhSqlDbType.Xml
) an SQL Server übergeben . Es wird angenommen, dass die Codierung die Standard-8-Bit-Codepage ist, wenn sie alsVARCHAR
(dhSqlDbType.VarChar
) übergeben wird. Wenn Sie Nicht-Standard-ASCII-Zeichen (dh Werte 128 und höher) haben und als übergebenVARCHAR
, wird wahrscheinlich "?" für BMP-Zeichen und "??" Für zusätzliche Zeichen konvertiert SQL Server die UTF-16-Zeichenfolge aus .NET in eine 8-Bit-Zeichenfolge der aktuellen Codepage der Datenbank, bevor sie wieder in UTF-16 / UCS-2 konvertiert wird. Aber Sie sollten keine Fehler bekommen.Wenn Sie andererseits die XML-Deklaration angeben, müssen Sie mit dem passenden 8-Bit- oder 16-Bit-Datentyp an SQL Server übergeben. Wenn Sie also eine Erklärung haben, dass die Codierung entweder UCS-2 oder UTF-16 ist, müssen Sie als
SqlDbType.NVarChar
oder übergebenSqlDbType.Xml
. Oder, wenn Sie eine Erklärung haben die besagt , dass die Codierung eine der 8-Bit - Optionen (dhUTF-8
,Windows-1252
,iso-8859-1
etc), dann Sie müssen in so passierenSqlDbType.VarChar
. Wenn die deklarierte Codierung nicht mit dem richtigen SQL Server-Datentyp mit 8 oder 16 Bit übereinstimmt, wird der Fehler "Codierung kann nicht geändert werden" angezeigt.Zum Beispiel habe
StringWriter
ich unter Verwendung Ihres basierten Serialisierungscodes einfach die resultierende Zeichenfolge des XML gedruckt und in SSMS verwendet. Wie Sie unten sehen können, ist die XML-Deklaration enthalten (daStringWriter
es keine Option zumOmitXmlDeclaration
LikenXmlWriter
gibt), was kein Problem darstellt, solange Sie die Zeichenfolge als korrekten SQL Server-Datentyp übergeben:Wie Sie sehen können, werden sogar Zeichen behandelt, die über das Standard-ASCII hinausgehen, vorausgesetzt, es
ሴ
handelt sich um den BMP-😸
Codepunkt U + 1234 und den zusätzlichen Zeichencodepunkt U + 1F638. Allerdings Folgendes:führt zu folgendem Fehler:
Abgesehen von all diesen Erklärungen lautet die vollständige Lösung Ihrer ursprünglichen Frage:
Sie haben die Zeichenfolge eindeutig als übergeben
SqlDbType.VarChar
. Wechseln Sie zuSqlDbType.NVarChar
und es funktioniert, ohne dass Sie den zusätzlichen Schritt zum Entfernen der XML-Deklaration ausführen müssen. Dies wird dem BeibehaltenSqlDbType.VarChar
und Entfernen der XML-Deklaration vorgezogen, da diese Lösung Datenverlust verhindert, wenn das XML Nicht-Standard-ASCII-Zeichen enthält. Beispielsweise:Wie Sie sehen können, gibt es diesmal keinen Fehler, aber jetzt gibt es Datenverlust 🙀.
quelle
SqlDbType.NVarChar
oder gewechseltXml
.Ein Problem
StringWriter
besteht darin, dass Sie standardmäßig nicht die Codierung festlegen können, für die angekündigt wird. Sie können also ein XML-Dokument erhalten, das die Codierung als UTF-16 ankündigt. Dies bedeutet, dass Sie es als UTF-16 codieren müssen, wenn Sie dies tun schreibe es in eine Datei. Ich habe eine kleine Klasse, die mir dabei hilft:Oder wenn Sie nur UTF-8 benötigen (das ist alles, was ich oft brauche):
Warum Sie Ihr XML nicht in der Datenbank speichern konnten, müssen Sie uns näher erläutern, was passiert ist, als Sie es versucht haben, damit wir es diagnostizieren / beheben können.
quelle
StringWriter
, dass die Kodierung nicht berücksichtigt wird, aber trotzdem, danke für eine nette kleine Methode :)MemoryStream
und aStreamWriter
mit der richtigen Codierung verwende.StreamWriter
ist schließlich einTextWriter
(der Typ, derXmlWriter.Create
erwartet) mit anpassbarer Codierung.Beim Serialisieren eines XML-Dokuments in eine .NET-Zeichenfolge muss die Codierung auf UTF-16 festgelegt werden. Zeichenfolgen werden intern als UTF-16 gespeichert, daher ist dies die einzige sinnvolle Codierung. Wenn Sie Daten in einer anderen Codierung speichern möchten, verwenden Sie stattdessen ein Byte-Array.
SQL Server arbeitet nach einem ähnlichen Prinzip. Jede in eine
xml
Spalte übergebene Zeichenfolge muss als UTF-16 codiert werden. SQL Server lehnt alle Zeichenfolgen ab, in denen in der XML-Deklaration kein UTF-16 angegeben ist. Wenn die XML-Deklaration nicht vorhanden ist, muss der XML-Standard standardmäßig UTF-8 verwenden, sodass SQL Server dies ebenfalls ablehnt.Vor diesem Hintergrund finden Sie hier einige nützliche Methoden für die Konvertierung.
quelle
StringWriter
Erwartungen entspricht. Siehe meine Antwort. Das interne Speicherformat spielt hier keine Rolle.Nothing
implizit in einen beliebigen Typ konvertierbar ist. Ich habe denDeserialize
Code korrigiert . DieSerialize
Warnung muss nur für Resharper gelten, der Compiler selbst hat keine Einwände und es ist legal, dies zu tun.Achten Sie zunächst darauf, alte Beispiele zu finden. Sie haben eine gefunden, die verwendet
XmlTextWriter
wird und ab .NET 2.0 veraltet ist.XmlWriter.Create
sollte stattdessen verwendet werden.Hier ist ein Beispiel für die Serialisierung eines Objekts in eine XML-Spalte:
quelle
XmlReader
sie analysiert werden kann. Es wird vorab analysiert an die Datenbank gesendet, und dann muss die Datenbank nichts über Zeichencodierungen wissen - UTF-16 oder andere. Beachten Sie insbesondere, dass die XML-Deklarationen nicht einmal mit den Daten in der Datenbank beibehalten werden, unabhängig davon, mit welcher Methode sie eingefügt werden. Machen Sie keine Verschwendung, indem Sie XML durch zusätzliche Konvertierungen ausführen, wie in anderen Antworten hier und anderswo gezeigt.quelle
Möglicherweise wurde es an anderer Stelle behandelt, aber durch einfaches Ändern der Codierungszeile der XML-Quelle in 'utf-16' kann das XML in den XML-Datentyp eines SQL Servers eingefügt werden.
Das Ergebnis ist, dass der gesamte XML-Text in das Datentypfeld 'xml' eingefügt wird, die Zeile 'header' jedoch entfernt wird. Was Sie in dem resultierenden Datensatz sehen, ist gerecht
Die Verwendung der im Eintrag "Beantwortet" beschriebenen Serialisierungsmethode ist eine Möglichkeit, den ursprünglichen Header in das Zielfeld aufzunehmen. Das Ergebnis ist jedoch, dass der verbleibende XML-Text in einem XML-
<string></string>
Tag enthalten ist.Der Tabellenadapter im Code ist eine Klasse, die automatisch mit dem Visual Studio 2013-Assistenten "Neue Datenquelle hinzufügen:" erstellt wird. Die fünf Parameter der Methode "Methode einfügen" werden Feldern in einer SQL Server-Tabelle zugeordnet.
quelle