【问题标题】:How to pass nvarchar (non-English) to CLR (C#) stored procedure?如何将 nvarchar(非英语)传递给 CLR(C#)存储过程?
【发布时间】:2016-08-23 06:34:09
【问题描述】:

在 Visual Studio 中工作时,我尝试使用 FOR XML RAW 和 C# 代码中的 SqlXml 类型的参数将整行传递给 CLR 存储过程(目的是使用 XmlReader 处理行)。该行包含 nvarchar 字段。

当 nvarchar 字段包含英语/数字/简单标点文本时,一切正常,但当其中任何一个包含希伯来语或俄语字符时,这些字符将变成问号。 (仅俄语文本也是如此,因此不是 RTL 问题)

从 SQL 代码中的打印中,我发现由 XML RAW 创建的 xml 保留了非英文字符——它们打印得很好。但是在打印 sqlXmlParameter.Value(或将其放入输出字符串并在 sql 中打印)时,会打印问号而不是非英文字符。 我尝试使用 SqlString 参数并得到相同的结果 - 该参数在 SQL 中看起来不错,但在传递给 CLR 过程时会发生变化。

我还发现 T-SQL 和 C# 都使用 UTF-16 作为默认编码,所以这真的很奇怪。

如何在将参数传递给 CLR 时保留非英文字符,或将编码信息附加到它们?

编辑:此问题涉及以下内容:How to make SqlContext.Pipe.Send in SQLCLR stored proc work with unicode? 事实证明,另一个问题的解决方案也解决了这个问题。我不知道为什么,因为这种情况下的 C# 代码不包含非英文字符,但它确实使用了可能是非英文字符串的字符串格式,所以可能是由于常量在字符串格式已保存。不过只是我的猜测。 因此,如果有人遇到相关问题(尽管我对它的定义模糊),您可能想尝试一下。

【问题讨论】:

  • 如何将 XML 从 RDBMS 传输到应用程序?
  • @Shnugo 我将 C# 代码添加为存储过程,并从 SQL 调用存储过程。据我所知,VS 将 C# 代码转换为程序集并自动创建将该程序集称为 EXTERNAL 的存储过程。
  • 是的,默认情况下,Windows / .NET / SQL Server ( NVARCHAR / NCHAR / XML ) 中的字符串是 UTF-16 Little Endian。从 XML 从 SQL Server 传输到 SQLCLR 对象(无论是传输到 SqlXml 还是 SqlString / SqlChars)时,字符不应发生变化。你试过SqlChars,它给你一个char[]吗?您可以从中创建一个新字符串:string _Test = new string(SqlCharsParam.Value);.
  • 你可能会发布一些代码?我见过与字符串操作人员相关的奇怪隐式转换(例如,添加根节点或顶级处理指令 (<? somthing ?>) 或组合 XML 部分时......
  • 另外,Windows 的 LCID 和包含 SQLCLR 代码的数据库的 LCID 是什么?运行以下命令:SELECT os_language_version, DATABASEPROPERTYEX(N'{name of DB where Assembly exists}', 'LCID') AS 'DatabaseLCID' FROM sys.dm_os_windows_info;

标签: .net stored-procedures sqlclr sqlxml non-english


【解决方案1】:

没有提供示例代码(调用存储过程的 C# 甚至 T-SQL),因此很难确定,但您可能在调用存储过程的方式上犯了错误。您很可能没有在 Unicode 和 XML 文字前加上 N 以将它们保持为 Unicode。以下 C# 代码和 T-SQL 表明 SQLCLR 确实可以在所有三种数据类型中正确接受和显示 Unicode 字符:SqlStringSqlCharsSqlXml(取自相关问题的示例希伯来语和俄语文本):

C#

using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public class UnicodeTesting
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void PrintTest(SqlString StringParam, SqlChars CharsParam,
                                 SqlXml XmlParam)
    {
        SqlContext.Pipe.Send("Unicode test: blip");
        SqlContext.Pipe.Send("Unicode test: בליפ");
        SqlContext.Pipe.Send("Unicode test: Блип");

        SqlContext.Pipe.Send("StringParam: " + StringParam.Value);
        SqlContext.Pipe.Send("CharsParam: " + new String(CharsParam.Value));
        SqlContext.Pipe.Send("XmlParam: " + XmlParam.Value);
    }
}

T-SQL

EXEC dbo.PrintTest N'בליפ a',
                   N'בליפ b',
                   N'<test>בליפ c</test><test>Блип</test>';

输出(在“消息”标签中)

Unicode test: blip
Unicode test: בליפ
Unicode test: Блип
StringParam: בליפ a
CharsParam: בליפ b
XmlParam: <test>בליפ c</test><test>Блип</test>

【讨论】:

  • 我将 FOR XML 的结果作为存储过程参数传递,并且该参数是 XML 类型,所以我不能直接将 N' 附加到该参数上。当我打印生成的 xml 以进行调试时,非英语看起来很好。服务器已关闭 atm,但我可以尝试将其作为 nvarchar 发送,以查看是否有帮助(会增加一些转换开销)。
  • @MASQ 你仍然太模糊,我无法真正提供帮助。我知道参数是 XML,但您显然是先将 FOR XML 的结果存储在变量中。您需要使用用于生成 XML 并调用 SQLCLR 存储过程的 T-SQL 更新问题。
  • 呃,我只是在我的工作上有点新,不知道关于其他人的代码(或任何)的政策是什么。我打算发布一个编辑过的代码示例,但看起来像更改 C# 代码上的保存设置(根据您对我的另一个问题的回答)以某种方式解决了这个问题。
  • @MASQ 我不需要 C# 代码(至少很可能不需要)。我只需要您正在测试的 T-SQL。执行 FOR XML 并调用存储过程的脚本。我不明白为什么更改 .cs 文件的编码会改变此问题中描述的行为。无论哪种方式,最好深入了解这一点并为其他人记录它。
  • 我也想知道为什么它也会有所不同,但这绝对是对原始代码的唯一更改(其他代码是在单独的项目中完成的)。我使用 XmlReader 读取 SqlXml,将其部分复制到字符串中,然后使用这些字符串从字符串格式中创建和执行 SqlCommands。字符串格式中的文字不包含非英文字符。当有来自 Xml 的非英语输入时,它会在格式中与字符串文字混合,我认为它可能符合文字的编码,可能是 ascii 或任何保存默认值。
猜你喜欢
  • 2013-02-19
  • 2011-09-15
  • 1970-01-01
  • 2016-06-09
  • 1970-01-01
  • 2014-01-29
  • 1970-01-01
  • 2016-06-14
相关资源
最近更新 更多