Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Cách giải quyết không thể chuyển đổi lỗi mã hóa khi chèn XML vào SQL Server

Câu hỏi này gần như trùng lặp với 2 câu hỏi khác và thật ngạc nhiên - trong khi câu hỏi này là câu hỏi gần đây nhất - tôi tin rằng nó thiếu câu trả lời tốt nhất.

Các bản sao và những gì tôi tin là câu trả lời tốt nhất của họ, là:

  • Sử dụng StringWriter để tuần tự hóa XML (2009-10-14)
    • https://stackoverflow.com/a/1566154/751158
  • Cố gắng lưu trữ nội dung XML vào SQL Server 2005 không thành công (sự cố mã hóa) (2008-12-21)
    • https://stackoverflow.com/a/1091209/751158

Cuối cùng, không có vấn đề gì về mã hóa được khai báo hoặc sử dụng, miễn là XmlReader có thể phân tích cú pháp cục bộ trong máy chủ ứng dụng.

Như đã được xác nhận trong Cách hiệu quả nhất để đọc XML trong ADO.net từ cột kiểu XML trong máy chủ SQL ?, Máy chủ SQL lưu trữ XML ở định dạng nhị phân hiệu quả. Bằng cách sử dụng SqlXml lớp, ADO.net có thể giao tiếp với SQL Server ở định dạng nhị phân này và không yêu cầu máy chủ cơ sở dữ liệu thực hiện bất kỳ tuần tự hóa hoặc hủy tuần tự hóa nào của XML. Điều này cũng sẽ hiệu quả hơn cho việc vận chuyển trên mạng.

Bằng cách sử dụng SqlXml , XML sẽ được gửi trước phân tích cú pháp đến cơ sở dữ liệu và sau đó DB không cần biết bất kỳ điều gì về mã hóa ký tự - UTF-16 hoặc cách khác. Đặc biệt, lưu ý rằng các khai báo XML thậm chí không được duy trì với dữ liệu trong cơ sở dữ liệu, bất kể phương pháp nào được sử dụng để chèn nó.

Vui lòng tham khảo các câu trả lời được liên kết ở trên để biết các phương pháp trông rất giống với phương pháp này, nhưng ví dụ này là của tôi:

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

Lưu ý rằng tôi sẽ không coi ví dụ cuối cùng (không được bình luận) là "sẵn sàng sản xuất", nhưng để nguyên như vậy để ngắn gọn và dễ đọc. Nếu được thực hiện đúng cách, cả StringReaderXmlReader đã tạo nên được khởi tạo trong using các câu lệnh để đảm bảo rằng Close() của chúng các phương thức được gọi khi hoàn tất.

Từ những gì tôi đã thấy, các khai báo XML không bao giờ tồn tại khi sử dụng một cột XML. Ví dụ:ngay cả khi không sử dụng .NET và chỉ sử dụng câu lệnh chèn SQL trực tiếp này, khai báo XML không được lưu vào cơ sở dữ liệu với XML:

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

Bây giờ theo câu hỏi của OP, đối tượng được tuần tự hóa vẫn cần được chuyển đổi thành cấu trúc XML từ MyMessage đối tượng và XmlSerializer vẫn cần thiết cho việc này. Tuy nhiên, tệ nhất là thay vì tuần tự hóa thành một chuỗi, thư thay vào đó có thể được tuần tự hóa thành một XmlDocument - sau đó có thể được chuyển tới SqlXml thông qua XmlNodeReader mới - tránh một chuyến đi hủy tuần tự hóa / tuần tự hóa thành một chuỗi. (Xem http://blogs.msdn.com/b/jongallant/archive/2007/01/30/how-to-convert-xmldocument-to-xmlreader-for-sqlxml-data-type.aspx để biết thêm chi tiết và ví dụ .)

Mọi thứ ở đây đều được phát triển và thử nghiệm với .NET 4.0 và SQL Server 2008 R2.

Xin đừng lãng phí bằng cách chạy XML thông qua các chuyển đổi bổ sung (de-deserializations và serializations - thành DOM, chuỗi hoặc cách khác), như được hiển thị trong các câu trả lời khác ở đây và ở những nơi khác.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách thay đổi một cột từ Null thành Not Null trong SQL Server

  2. Hàm ROUND () của SQL Server:Điều gì cần làm và Tại sao bạn nên quan tâm?

  3. Cách xóa các ký tự đứng đầu và theo sau trong SQL Server

  4. Tại sao tôi không thể sử dụng bí danh trong cột đếm (*) và tham chiếu nó trong mệnh đề có?

  5. Tôi có nên thiết kế một bảng với khóa chính là varchar hoặc int?