<TL; DR> समस्या वास्तव में सरल है, वास्तव में: आप इनपुट पैरामीटर के डेटाटाइप के साथ घोषित एन्कोडिंग (XML घोषणा में) का मिलान नहीं कर रहे हैं। यदि आपने मैन्युअल रूप <?xml version="1.0" encoding="utf-8"?><test/>
से स्ट्रिंग में जोड़ा है, तो SqlParameter
प्रकार की घोषणा करना SqlDbType.Xml
या SqlDbType.NVarChar
आपको "एन्कोडिंग को स्विच करने में असमर्थ" त्रुटि देगा। तब, जब आप टी-एसक्यूएल के माध्यम से मैन्युअल रूप से सम्मिलित करते हैं, चूंकि आपने घोषित एन्कोडिंग को स्विच किया था utf-16
, तो आप स्पष्ट रूप से एक VARCHAR
स्ट्रिंग डाल रहे थे (ऊपरी-मामले "एन" के साथ उपसर्ग नहीं किया गया था, इसलिए 8-बिट एन्कोडिंग, जैसे कि यूटीएफ -8) और नहीं एNVARCHAR
स्ट्रिंग (एक ऊपरी-केस "एन" के साथ उपसर्ग किया गया, इसलिए 16-बिट UTF-16 LE एन्कोडिंग)।
यह फिक्स जितना सरल होना चाहिए था:
- पहले मामले में, जब घोषणा को बताते हुए कहते हैं
encoding="utf-8"
: बस XML घोषणा को न जोड़ें।
- दूसरे मामले में, जब घोषणा को बताते हुए कहा
encoding="utf-16"
: या तो
- बस एक्सएमएल घोषणा को जोड़ नहीं है, या
- बस इनपुट पैरामीटर प्रकार में एक "एन" जोड़ें:
SqlDbType.NVarChar
बजाय SqlDbType.VarChar
:-) (या संभवतः भी उपयोग करने के लिए स्विच SqlDbType.Xml
)
(विस्तृत प्रतिक्रिया नीचे है)
यहां सभी उत्तर अति-जटिल और अनावश्यक हैं (ईसाई और जॉन के जवाबों के लिए क्रमशः 121 और 184 वोटों की परवाह किए बिना)। वे कार्य कोड प्रदान कर सकते हैं, लेकिन उनमें से कोई भी वास्तव में सवाल का जवाब नहीं देता है। मुद्दा यह है कि कोई भी वास्तव में प्रश्न को नहीं समझ पाया है, जो कि आखिरकार SQL सर्वर में XML डेटाटाइप कैसे काम करता है। उन दो स्पष्ट रूप से बुद्धिमान लोगों के खिलाफ कुछ भी नहीं है, लेकिन इस सवाल का एक्सएमएल को क्रमबद्ध करने से कोई लेना-देना नहीं है। XML डेटा को SQL सर्वर में सहेजना यहाँ पर निहित होने की तुलना में बहुत आसान है।
यह वास्तव में कोई फर्क नहीं पड़ता कि जब तक आप SQL सर्वर में XML डेटा बनाने के नियमों का पालन करते हैं तब तक XML का उत्पादन कैसे किया जाता है। इस प्रश्न पर एक उत्तर में मेरे पास अधिक गहन स्पष्टीकरण है (नीचे उल्लिखित बिंदुओं को चित्रित करने के लिए कार्य उदाहरण कोड सहित): XML सर्वर को SQL सर्वर में सम्मिलित करते समय "एन्कोडिंग को स्विच करने में असमर्थ" त्रुटि को कैसे हल करें , लेकिन मूल बातें हैं:
- एक्सएमएल घोषणा वैकल्पिक है
- XML डेटाटाइप हमेशा UCS-2 / UTF-16 LE के रूप में तार संग्रहीत करता है
- यदि आपका XML UCS-2 / UTF-16 LE है, तो आप:
NVARCHAR(MAX)
या तो डेटा के रूप में पास करें या XML
/ SqlDbType.NVarChar
(अधिकतम = -1) या SqlDbType.Xml
, या यदि एक स्ट्रिंग शाब्दिक का उपयोग कर रहे हैं तो इसे ऊपरी-मामले "एन" के साथ उपसर्ग करना होगा।
- यदि XML घोषणा को निर्दिष्ट किया जाता है, तो यह "UCS-2" या "UTF-16" होना चाहिए (यहां कोई वास्तविक अंतर नहीं है)
- यदि आपका XML 8-बिट एनकोडेड है (जैसे "UTF-8" / "iso-8859-1" / "Windows-1252"), तो आप:
- XML घोषणा को निर्दिष्ट करने की आवश्यकता है यदि एन्कोडिंग डेटाबेस के डिफ़ॉल्ट Collation द्वारा निर्दिष्ट कोड पृष्ठ से अलग है
- आपको डेटा को
VARCHAR(MAX)
/ SqlDbType.VarChar
(अधिकतम -१ =) के रूप में पास करना होगा , या यदि एक स्ट्रिंग शाब्दिक का उपयोग करना है, तो इसे ऊपरी-केस "एन" के साथ उपसर्ग नहीं करना चाहिए ।
- जो भी 8-बिट एन्कोडिंग का उपयोग किया जाता है, एक्सएमएल घोषणा में उल्लेखित "एन्कोडिंग" बाइट्स के वास्तविक एन्कोडिंग से मेल खाना चाहिए।
- 8-बिट एन्कोडिंग को XML डेटाटाइप द्वारा UTF-16 LE में परिवर्तित किया जाएगा
मन में ऊपर उल्लिखित बिंदुओं के साथ, और .NET में तार हमेशा UTF-16 LE / UCS-2 LE होते हैं (एन्कोडिंग के संदर्भ में उन लोगों के बीच कोई अंतर नहीं है), हम आपके सवालों का जवाब दे सकते हैं:
वहाँ एक कारण है कि मैं एक वस्तु को क्रमबद्ध करने के लिए स्ट्रिंगराइटर का उपयोग नहीं करना चाहिए जब मुझे बाद में स्ट्रिंग के रूप में इसकी आवश्यकता होती है?
नहीं, आपका StringWriter
कोड ठीक प्रतीत होता है (कम से कम मुझे सवाल से 2 कोड ब्लॉक का उपयोग करके अपने सीमित परीक्षण में कोई समस्या नहीं दिखती है)।
तब UTF-16 (xml टैग में) को एन्कोडिंग सेट नहीं किया जाएगा?
XML घोषणा प्रदान करना आवश्यक नहीं है। यदि यह अनुपलब्ध है, तो एन्कोडिंग को UTF-16 LE माना जाता है यदि आप स्ट्रिंग को SQL सर्वर में NVARCHAR
(जैसे SqlDbType.NVarChar
) या XML
(यानी SqlDbType.Xml
) पास करते हैं। एन्कोडिंग को डिफ़ॉल्ट 8-बिट कोड पृष्ठ माना जाता है यदि वह VARCHAR
(यानी SqlDbType.VarChar
) में गुजर रहा है । यदि आपके पास कोई गैर-मानक-एएससीआईआई अक्षर हैं (अर्थात मान 128 और उससे अधिक) और जैसे-जैसे गुजर रहे हैं VARCHAR
, तो आप "" की संभावना करेंगे? BMP वर्ण और "??" के लिए SQL सर्वर के रूप में पूरक वर्णों के लिए UTF-16 / UCS-2 में वापस परिवर्तित करने से पहले SQL सर्वर UTF-16 स्ट्रिंग को .NET से वर्तमान डेटाबेस के कोड पेज के 8-बिट स्ट्रिंग में बदल देगा। लेकिन आपको कोई त्रुटि नहीं मिलनी चाहिए।
दूसरी ओर, यदि आप एक्सएमएल घोषणा को निर्दिष्ट करते हैं, तो आपको 8-बिट या 16-बिट डेटाटाइप का उपयोग करके SQL सर्वर में पास होना चाहिए । इसलिए यदि आपके पास यह घोषणा है कि एन्कोडिंग यूसीएस -2 या यूटीएफ -16 है, तो आपको या में पास होना चाहिए । या, यदि आप एक घोषणा करते हुए कहा कि एन्कोडिंग 8 बिट विकल्पों में से एक (यानी है अगर , , , आदि) है, तो आप चाहिए के रूप में में पारित । उचित 8 या 16-बिट एसक्यूएल सर्वर डेटाटाइप के साथ घोषित एन्कोडिंग से मेल करने में विफलता के परिणामस्वरूप "एन्कोडिंग को स्विच करने में असमर्थ" त्रुटि होगी जो आपको मिल रही थी।SqlDbType.NVarChar
SqlDbType.Xml
UTF-8
Windows-1252
iso-8859-1
SqlDbType.VarChar
उदाहरण के लिए, आपके- StringWriter
आधारित सीरियल कोड का उपयोग करते हुए , मैंने बस XML के परिणामी स्ट्रिंग को प्रिंट किया और SSMS में इसका उपयोग किया। आप नीचे देख सकते हैं, XML घोषणा शामिल है (क्योंकि StringWriter
के लिए एक विकल्प नहीं है OmitXmlDeclaration
की तरह XmlWriter
है, जो इतने लंबे समय के रूप में आप सही एसक्यूएल सर्वर डेटाप्रकार के रूप में स्ट्रिंग पारित नहीं समस्या बन गया है करता है):
-- Upper-case "N" prefix == NVARCHAR, hence no error:
DECLARE @Xml XML = N'<?xml version="1.0" encoding="utf-16"?>
<string>Test ሴ😸</string>';
SELECT @Xml;
-- <string>Test ሴ😸</string>
जैसा कि आप देख सकते हैं, यह मानक ASCII से परे वर्णों को भी संभालता है, यह देखते हुए कि ሴ
BMP कोड प्वाइंट U + 1234 है, और 😸
पूरक चरित्र कोड प्वाइंट U + 1F638 है। हालांकि, निम्नलिखित:
-- No upper-case "N" prefix on the string literal, hence VARCHAR:
DECLARE @Xml XML = '<?xml version="1.0" encoding="utf-16"?>
<string>Test ሴ😸</string>';
निम्नलिखित त्रुटि के परिणाम:
Msg 9402, Level 16, State 1, Line XXXXX
XML parsing: line 1, character 39, unable to switch the encoding
एर्गो, उस स्पष्टीकरण के सभी एक तरफ, आपके मूल प्रश्न का पूर्ण समाधान है:
आप स्पष्ट रूप से स्ट्रिंग को पास कर रहे थे SqlDbType.VarChar
। स्विच करें SqlDbType.NVarChar
और यह XML घोषणा को हटाने के अतिरिक्त चरण के माध्यम से जाने की आवश्यकता के बिना काम करेगा। यह SqlDbType.VarChar
XML घोषणा को रखने और हटाने से अधिक पसंद किया जाता है क्योंकि यह समाधान डेटा हानि को रोक देगा जब XML में गैर-मानक-ASCII वर्ण शामिल होते हैं। उदाहरण के लिए:
-- No upper-case "N" prefix on the string literal == VARCHAR, and no XML declaration:
DECLARE @Xml2 XML = '<string>Test ሴ😸</string>';
SELECT @Xml2;
-- <string>Test ???</string>
जैसा कि आप देख सकते हैं, इस बार कोई त्रुटि नहीं है, लेकिन अब डेटा-लॉस है।