Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 如何通过SqlDataReader获取结果集中字符串字段的排序规则?_.net_Sql Server_Collation_Sqldatareader_Sqlclr - Fatal编程技术网

.net 如何通过SqlDataReader获取结果集中字符串字段的排序规则?

.net 如何通过SqlDataReader获取结果集中字符串字段的排序规则?,.net,sql-server,collation,sqldatareader,sqlclr,.net,Sql Server,Collation,Sqldatareader,Sqlclr,从中检索结果集时,可以使用该方法获取该结果集的大部分元数据。然而,缺少的一点是字符串字段的排序(即CHAR,VARCHAR,NCHAR,NVARCHAR,SQL\u VARIANT——如果包含字符串类型——甚至是不推荐使用的文本和NTEXT)。有没有办法得到这些信息 虽然技术上可以调用具有LCID和SqlCompareOptions属性的方法,但这些属性返回与数据库默认排序规则相关的值,该排序规则可能是也可能不是任何特定字段的排序规则(尽管大多数人似乎只是假设它是相同的)或表达(由于)。这些属性

从中检索结果集时,可以使用该方法获取该结果集的大部分元数据。然而,缺少的一点是字符串字段的排序(即
CHAR
VARCHAR
NCHAR
NVARCHAR
SQL\u VARIANT
——如果包含字符串类型——甚至是不推荐使用的
文本和
NTEXT
)。有没有办法得到这些信息

虽然技术上可以调用具有
LCID
SqlCompareOptions
属性的方法,但这些属性返回与数据库默认排序规则相关的值,该排序规则可能是也可能不是任何特定字段的排序规则(尽管大多数人似乎只是假设它是相同的)或表达(由于)。这些属性仅在源数据类型为
SQL\u VARIANT
时提供准确信息,这并没有太大帮助

没有这些额外信息(至少相当于区域设置的“LCID”)的问题在于,尽管所有字符,无论源编码如何,都可以在.NET中表示,而不会丢失(因为.NET字符串是UTF-16小端),将结果集中的字段与其他字符串进行比较时,无法确定要使用的区域设置

每个字符串字段的排序规则信息肯定是SQL Server通过TDS流发送到客户端的数据流的一部分。它用于:

  • 通过
    SqlDataReader
    类的方法公开
    LCID
    。但是该方法被标记为
    internal
    ,因此我无法访问它。它似乎只在一个地方使用:
  • 为SQLCLR存储过程和触发器中使用的
    SqlPipe
    方法提供结果集结构
  • 根据情况,使用
    SqlDataReader
    的方法设置正确的
    编码。但是,尽管该方法是
    public
    ,但
    TextReader
    类没有
    编码的属性;编码信息仅在内部使用
更新

澄清一下:我们希望有一种获取此信息的方法,而不需要程序集完全受信任/
不安全
。预期用途是在控制台应用程序和SQLCLR对象(存储过程、函数等)中运行的代码。如果程序集(加载到SQL Server中时)需要具有
外部访问的
权限集
,则可以接受。但是,要求将SQLCLR程序集标记为不安全将不起作用

最终的最高理想是获得SQL Server中存在的完整排序规则名称(例如,
Latin1\u General\u 100\u BIN2
),并将SQL Server中的程序集标记为
SAFE

更新2

按照@Jonathan的说法,使用反射可以调用“internal”
GetLocaleId
方法,并返回正确的LCID。但是,在SQLCLR对象中使用此代码时,如果程序集未标记为
不安全
,则会出现以下异常:

Msg 6522,第16级,状态1,第9行
在执行用户定义例程或聚合“GetFieldCollation”期间发生.NET Framework错误:

System.MethodAccessException:尝试通过方法“UserDefinedFunctions.GetFieldCollation(System.Data.SqlTypes.SqlString,System.Data.SqlTypes.SqlBoolean)”访问方法“System.Data.SqlClient.SqlDataReader.GetLocaleId(Int32)”失败

System.MethodAccessException:
在System.RuntimeMethodHandle.PerformSecurityCheck(对象对象对象、RuntimeMethodHandleInternal方法、RuntimeType父对象、UInt32调用标志)中
在System.RuntimeMethodHandle.PerformSecurityCheck(对象对象对象、IRuntimeMethodInfo方法、RuntimeType父对象、UInt32调用标志)中
在System.Reflection.RuntimeMethodInfo.Invoke(对象obj、BindingFlags invokeAttr、绑定器绑定器、对象[]参数、文化信息文化)
在System.Reflection.MethodBase.Invoke(对象obj,对象[]参数)处

看看这篇MSDN文章,它甚至提到(重点补充):

向沙盒域添加受限成员访问权限

例如,主机可能会向Internet应用程序授予Internet权限和RMA,以便Internet应用程序可以发出访问其自身程序集中私有数据的代码。由于访问仅限于具有相等或较小信任的程序集,因此Internet应用程序无法访问完全信任的程序集(如.NET Framework程序集)的成员

不幸的是,要求程序集
不安全
违背了要求

老实说,这只是整个谜题的一部分。正如在第一个更新部分中所述,我们的目标是拥有这个和真正的排序规则名称,而这个名称目前似乎不存在于任何地方。因此,我向Microsoft发送了以下建议:

通过SqlDataReader公开SQL Server结果集的排序规则信息(由于visualstudio.uservoice.com被关闭,链接不再有效)

更新3

澄清:理想情况下,会有一个方法或属性返回用于给定字符串字段的精确排序规则(例如,
Latin1\u General\u 100\u CI\u AS\u KS\u WS\u SC
)。但是,仅仅公开
LCID
SqlCompareOptions
可能不够好,因为这些属性不能传递以下信息:

  • 排序规则版本(当前为80(即未指定)、90、100或140/甚至备用的0、1、2或3就足够了)
  • \u-BIN
    vs
    \u-BIN2
  • CodePage
  • \u VSS
    (变量选择器敏感;启动
    var method = typeof (SqlDataReader).GetMethod("GetLocaleId", BindingFlags.NonPublic | BindingFlags.Instance);
    using (var conn = new SqlConnection(My.Config.ConnectionStrings.SqlConnection))
    {
        using (var command = new SqlCommand("SELECT TOP 0 * FROM TestTable", conn))
        {
            conn.Open();
            using (SqlDataReader reader = command.ExecuteReader())
            {
                var schema = reader.GetSchemaTable();
    
                // 1033 = Latin1_General_CI_AS (confirmed)
                var collation2 = method.Invoke(reader, new object[] { 2 });
    
                // 1048 = Romanian_CI_AS (Current : SQL_Romanian_CP1250_CI_AS, close enough!)
                var collation3 = method.Invoke(reader, new object[] { 3 });
            }
        }
    }
    
    // using Z.Expressions;
    
    var getLocalIdCompiled = Eval.Compile<Func<SqlDataReader, int, int>>("reader.GetLocaleId(value)", "reader", "value");
    
    using (var conn = new SqlConnection(My.Config.ConnectionStrings.SqlConnection))
    {
        using (var command = new SqlCommand("SELECT TOP 0 * FROM TestTable", conn))
        {
            conn.Open();
            using (SqlDataReader reader = command.ExecuteReader())
            {
                var schema = reader.GetSchemaTable();
    
                var collation2 = getLocalIdCompiled(reader, 2);
                var collation3 = getLocalIdCompiled(reader, 3);
            }
        }
    }