Saya sedang mencari cara mudah untuk membuat serial objek (di C # 3).
Saya mencari beberapa contoh di Google dan menemukan sesuatu seperti:
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());
Setelah membaca pertanyaan ini saya bertanya pada diri sendiri, mengapa tidak menggunakan StringWriter? Sepertinya jauh lebih mudah.
XmlSerializer ser = new XmlSerializer(typeof(MyObject));
StringWriter writer = new StringWriter();
ser.Serialize(writer, myObject);
serializedValue = writer.ToString();
Masalah lain adalah, bahwa contoh pertama menghasilkan XML Saya tidak bisa begitu saja menulis ke dalam kolom XML SQL Server 2005 DB.
Pertanyaan pertama adalah: Apakah ada alasan mengapa saya tidak boleh menggunakan StringWriter untuk membuat serial Objek ketika saya membutuhkannya sebagai string sesudahnya? Saya tidak pernah menemukan hasil menggunakan StringWriter saat googling.
Yang kedua, tentu saja: Jika Anda tidak boleh melakukannya dengan StringWriter (karena alasan apa pun), mana yang merupakan cara yang baik dan benar?
Tambahan:
Seperti yang telah disebutkan oleh kedua jawaban, selanjutnya saya akan membahas masalah XML ke DB.
Saat menulis ke Database saya mendapat pengecualian berikut:
System.Data.SqlClient.SqlException: XML parsing: baris 1, karakter 38, tidak dapat mengalihkan pengkodean
Untuk string
<?xml version="1.0" encoding="utf-8"?><test/>
Saya mengambil string yang dibuat dari XmlTextWriter dan meletakkannya sebagai xml di sana. Yang ini tidak berhasil (tidak dengan penyisipan manual ke DB).
Setelah itu saya mencoba penyisipan manual (hanya menulis INSERT INTO ...) dengan encoding = "utf-16" yang juga gagal. Menghapus pengkodean benar-benar berfungsi saat itu. Setelah hasil itu saya beralih kembali ke kode Penulis String dan voila - itu berhasil.
Masalah: Saya tidak begitu mengerti mengapa.
di Christian Hayter: Dengan tes tersebut saya tidak yakin apakah saya harus menggunakan utf-16 untuk menulis ke DB. Tidakkah pengaturan encoding ke UTF-16 (dalam tag xml) akan berfungsi?
sumber
Jawaban:
<TL; DR> Masalahnya cukup sederhana, sebenarnya: Anda tidak mencocokkan pengkodean yang dinyatakan (dalam deklarasi XML) dengan tipe data dari parameter input. Jika Anda menambahkan
<?xml version="1.0" encoding="utf-8"?><test/>
ke string secara manual , maka mendeklarasikanSqlParameter
menjadi tipeSqlDbType.Xml
atauSqlDbType.NVarChar
akan memberi Anda kesalahan "tidak dapat mengalihkan pengkodean". Kemudian, saat memasukkan secara manual melalui T-SQL, karena Anda mengganti encoding yang dideklarasikan menjadiutf-16
, Anda dengan jelas memasukkanVARCHAR
string (tidak diawali dengan huruf besar "N", karenanya encoding 8-bit, seperti UTF-8) dan bukan sebuahNVARCHAR
string (diawali dengan huruf besar "N", karenanya pengkodean UTF-16 LE 16-bit).Perbaikannya seharusnya sesederhana:
encoding="utf-8"
: jangan tambahkan deklarasi XML.encoding="utf-16"
: baikSqlDbType.NVarChar
alih-alihSqlDbType.VarChar
:-) (atau bahkan mungkin beralih menggunakanSqlDbType.Xml
)(Tanggapan rinci ada di bawah)
Semua jawaban di sini terlalu rumit dan tidak perlu (terlepas dari 121 dan 184 suara untuk jawaban Christian dan Jon, masing-masing). Mereka mungkin memberikan kode yang berfungsi, tetapi tidak satupun dari mereka benar-benar menjawab pertanyaan tersebut. Masalahnya adalah tidak ada yang benar-benar memahami pertanyaan tersebut, yang pada akhirnya adalah tentang cara kerja tipe data XML di SQL Server. Tidak ada yang menentang kedua orang yang jelas cerdas itu, tetapi pertanyaan ini tidak ada hubungannya dengan serialisasi ke XML. Menyimpan data XML ke SQL Server jauh lebih mudah daripada yang tersirat di sini.
Tidak masalah bagaimana XML diproduksi selama Anda mengikuti aturan cara membuat data XML di SQL Server. Saya memiliki penjelasan yang lebih menyeluruh (termasuk kode contoh yang berfungsi untuk mengilustrasikan poin yang diuraikan di bawah) dalam jawaban atas pertanyaan ini: Bagaimana mengatasi kesalahan "tidak dapat mengganti pengkodean" saat memasukkan XML ke SQL Server , tetapi dasarnya adalah:
NVARCHAR(MAX)
atauXML
/SqlDbType.NVarChar
(maxsize = -1) atauSqlDbType.Xml
, atau jika menggunakan literal string maka harus diawali dengan huruf besar "N".VARCHAR(MAX)
/SqlDbType.VarChar
(maxsize = -1), atau jika menggunakan string literal maka tidak boleh diawali dengan huruf besar "N".Dengan memperhatikan poin-poin yang diuraikan di atas, dan mengingat bahwa string dalam .NET selalu UTF-16 LE / UCS-2 LE (tidak ada perbedaan di antara keduanya dalam hal encoding), kami dapat menjawab pertanyaan Anda:
Tidak,
StringWriter
kode Anda tampaknya baik-baik saja (setidaknya saya tidak melihat masalah dalam pengujian terbatas saya menggunakan blok kode ke-2 dari pertanyaan).Tidak perlu memberikan deklarasi XML. Jika tidak ada, pengkodean dianggap UTF-16 LE jika Anda meneruskan string ke SQL Server sebagai
NVARCHAR
(yaituSqlDbType.NVarChar
) atauXML
(yaituSqlDbType.Xml
). Pengkodean diasumsikan sebagai Halaman Kode 8-bit default jika dikirimkan sebagaiVARCHAR
(yaituSqlDbType.VarChar
). Jika Anda memiliki karakter non-standar-ASCII (yaitu nilai 128 ke atas) dan mengirimkan sebagaiVARCHAR
, maka Anda mungkin akan melihat "?" untuk karakter BMP dan "??" untuk Karakter Tambahan karena SQL Server akan mengubah string UTF-16 dari .NET menjadi string 8-bit dari Halaman Kode Database saat ini sebelum mengubahnya kembali menjadi UTF-16 / UCS-2. Tetapi Anda seharusnya tidak mendapatkan kesalahan apa pun.Di sisi lain, jika Anda menentukan deklarasi XML, maka Anda harus meneruskan ke SQL Server menggunakan tipe data 8-bit atau 16-bit yang cocok. Jadi, jika Anda memiliki deklarasi yang menyatakan bahwa encodingnya adalah UCS-2 atau UTF-16, Anda harus meneruskan sebagai
SqlDbType.NVarChar
atauSqlDbType.Xml
. Atau, jika Anda memiliki sebuah deklarasi yang menyatakan bahwa pengkodean adalah salah satu pilihan 8-bit (yaituUTF-8
,Windows-1252
,iso-8859-1
, dll), maka Anda harus lulus dalam sebagaiSqlDbType.VarChar
. Kegagalan untuk mencocokkan pengkodean yang dinyatakan dengan tipe data SQL Server 8 atau 16-bit yang tepat akan mengakibatkan kesalahan "tidak dapat mengalihkan pengkodean" yang Anda dapatkan.Misalnya, menggunakan
StringWriter
kode serialisasi berbasis Anda , saya hanya mencetak string yang dihasilkan dari XML dan menggunakannya di SSMS. Seperti yang Anda lihat di bawah, deklarasi XML disertakan (karenaStringWriter
tidak memiliki opsi untukOmitXmlDeclaration
sukaXmlWriter
), yang tidak menimbulkan masalah selama Anda meneruskan string sebagai tipe data SQL Server yang benar:Seperti yang Anda lihat, ia bahkan menangani karakter di luar ASCII standar, mengingat itu
ሴ
adalah BMP Code Point U + 1234, dan😸
Supplementary Character Code Point U + 1F638. Namun, berikut ini:menghasilkan kesalahan berikut:
Ergo, selain semua penjelasan itu, solusi lengkap untuk pertanyaan awal Anda adalah:
Anda dengan jelas memasukkan string sebagai
SqlDbType.VarChar
. Beralih keSqlDbType.NVarChar
dan ini akan berfungsi tanpa perlu melalui langkah tambahan untuk menghapus deklarasi XML. Ini lebih disukai daripada menyimpanSqlDbType.VarChar
dan menghapus deklarasi XML karena solusi ini akan mencegah kehilangan data ketika XML menyertakan karakter non-standar-ASCII. Sebagai contoh:Seperti yang Anda lihat, tidak ada kesalahan kali ini, tetapi sekarang ada kehilangan data 🙀.
sumber
SqlDbType.NVarChar
atauXml
.Satu masalah dengan
StringWriter
adalah bahwa secara default itu tidak memungkinkan Anda mengatur pengkodean yang diiklankan - sehingga Anda dapat berakhir dengan dokumen XML yang mengiklankan pengkodeannya sebagai UTF-16, yang berarti Anda perlu menyandikannya sebagai UTF-16 jika Anda tulis ke file. Saya memiliki kelas kecil untuk membantu dengan itu:Atau jika Anda hanya membutuhkan UTF-8 (yang sering saya butuhkan):
Adapun mengapa Anda tidak dapat menyimpan XML Anda ke database - Anda harus memberi kami detail lebih lanjut tentang apa yang terjadi ketika Anda mencoba, jika Anda ingin kami dapat mendiagnosis / memperbaikinya.
sumber
StringWriter
tidak memperhitungkan pengkodean, tetapi tidak pernah kurang, terima kasih untuk metode kecil yang bagus :)MemoryStream
dan aStreamWriter
dengan pengkodean yang benar.StreamWriter
adalah sebuahTextWriter
(jenis yangXmlWriter.Create
mengharapkan) dengan encoding disesuaikan, setelah semua.Saat menserialisasikan dokumen XML ke string .NET, pengkodean harus disetel ke UTF-16. String disimpan sebagai UTF-16 secara internal, jadi ini adalah satu-satunya pengkodean yang masuk akal. Jika Anda ingin menyimpan data dalam pengkodean yang berbeda, Anda menggunakan array byte sebagai gantinya.
SQL Server bekerja dengan prinsip serupa; string apa pun yang dilewatkan ke dalam
xml
kolom harus dikodekan sebagai UTF-16. SQL Server akan menolak string apa pun jika deklarasi XML tidak menentukan UTF-16. Jika deklarasi XML tidak ada, standar XML mengharuskannya default ke UTF-8, jadi SQL Server juga akan menolaknya.Mengingat hal ini, berikut adalah beberapa metode utilitas untuk melakukan konversi.
sumber
StringWriter
diharapkan. Lihat jawaban saya. Format penyimpanan internal tidak relevan di sini.Nothing
secara implisit dapat dikonversi ke jenis apa pun. Saya telah mengoreksiDeserialize
kodenya. TheSerialize
peringatan harus Resharper-satunya, compiler sendiri tidak keberatan dan itu legal untuk dilakukan.Pertama-tama, berhati-hatilah dalam menemukan contoh lama. Anda telah menemukan salah satu yang menggunakan
XmlTextWriter
, yang dihentikan sejak .NET 2.0.XmlWriter.Create
harus digunakan sebagai gantinya.Berikut adalah contoh serialisasi objek ke dalam kolom XML:
sumber
XmlReader
dapat menguraikannya. Ini akan dikirim pra-parsing ke database, dan kemudian DB tidak perlu tahu apa-apa tentang pengkodean karakter - UTF-16 atau sebaliknya. Secara khusus, perhatikan bahwa deklarasi XML bahkan tidak disimpan dengan data dalam database, terlepas dari metode mana yang digunakan untuk menyisipkannya. Harap jangan sia-siakan dengan menjalankan XML melalui konversi tambahan, seperti yang ditunjukkan dalam jawaban lain di sini dan di tempat lain.sumber
Ini mungkin telah dibahas di tempat lain tetapi hanya dengan mengubah baris pengkodean sumber XML ke 'utf-16' memungkinkan XML untuk dimasukkan ke dalam jenis xml'data SQL Server.
Hasilnya adalah semua teks XML dimasukkan ke dalam bidang tipe data 'xml' tetapi baris 'tajuk' dihapus. Apa yang Anda lihat dalam rekaman yang dihasilkan adalah adil
Menggunakan metode serialisasi yang dijelaskan dalam entri "Dijawab" adalah cara untuk memasukkan header asli ke dalam bidang target, tetapi hasilnya adalah teks XML yang tersisa diapit dalam
<string></string>
tag XML .Adaptor tabel dalam kode adalah kelas yang secara otomatis dibangun menggunakan "Add New Data Source: wizard" Visual Studio 2013 Lima parameter untuk metode sisipkan peta ke bidang dalam tabel SQL Server.
sumber