我正在尝试转换回存储在CONTEXT_INFO中的nvarchar。
declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(@LanguageCode as varbinary);
set context_info @binvar;
select A = len(@LanguageCode);
select B = len(convert(nvarchar(6),@LanguageCode));
select C = convert(nvarchar(6),context_info());
select D = cast(CONTEXT_INFO() as nvarchar(5));
select E = len(convert(nvarchar(6),CONTEXT_INFO()));
select F =len(cast(CONTEXT_INFO() as nvarchar(6)));
select G = convert(nvarchar,context_info());
select H = cast(CONTEXT_INFO() as nvarchar);
select I = len(convert(nvarchar,CONTEXT_INFO()));
select J = len(cast(CONTEXT_INFO() as nvarchar));
从将varbinary转换为nvarchar获得的nvarchar的长度为6,它包含\ 0。例如,语言'en'以'en \ 0 \ 0 \ 0 \ 0'的形式获得。这破坏了NHibernate上的密钥缓存。
有没有办法可以将varbinary中存储的nvarchar值转换回原始值?即'en'可以转换回'en'。
输出:
A
-----------
2
B
-----------
2
C
------
en
D
-----
en
E
-----------
6
F
-----------
6
G
------------------------------
en
H
------------------------------
en
I
-----------
30
J
-----------
30
CHOSEN ANSWER理由
我选择了HABO的答案,因为他的解决方案可直接嵌入到消费查询中:
declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(datalength(@LanguageCode) as varbinary) + cast(@LanguageCode as varbinary);
set context_info @binvar;
select dump = @binvar;
-- directly embeddable
select recoveredLanguage = convert(nvarchar, substring(context_info(), 5, convert(int, substring(context_info(), 1, 4)) ) )
, theLength = len ( convert(nvarchar, substring(context_info(), 5, convert(int, substring(context_info(), 1, 4)) ) ) )
declare @buffer varbinary(128) = context_info();
declare @RecoveredLanguageCode nvarchar(6) = cast(substring(@buffer, 5, cast(substring(@buffer, 1, 4) as int)) as nvarchar(6));
select recoveredLanguage = @RecoveredLanguageCode, theLength = len(@RecoveredLanguageCode);
输出:
dump
--------------------
0x0000000465006E00
(1 row(s) affected)
recoveredLanguage theLength
------------------------------ -----------
en 2
(1 row(s) affected)
recoveredLanguage theLength
----------------- -----------
en 2
(1 row(s) affected)
虽然souplex的答案是正确的,但我不确定SET ANSI_PADDING_OFF是全局影响还是仅局部影响一批语句。将所有铸件放在一个陈述中会产生副作用,恢复不起作用,每个铸件必须在单独的陈述中完成。无论如何,我赞成了汤米克斯的答案
DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;
select dump = @Binvar;
SET ANSI_PADDING OFF;
select recoveredLanguage = cast( cast( cast(context_info() as binary(128)) as varbinary(128) ) as nvarchar(6) )
, theLength = len( cast( cast( cast(context_info() as binary(128)) as varbinary(128) ) as nvarchar(6) ) );
DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
declare @c nvarchar(6) = cast(@binvar2 as nvarchar(6))
select recoveredLanguage = @c, theLength = len(@c);
输出:
dump
----------
0x65006E00
(1 row(s) affected)
recoveredLanguage theLength
----------------- -----------
en 6
(1 row(s) affected)
recoveredLanguage theLength
----------------- -----------
en 2
(1 row(s) affected)
感谢HABO和souplex没有提出XML PATH或XML AUTO解决方案:-)谢谢!
答案 0 :(得分:3)
在将字符串保存到CONTEXT_INFO
:
declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(datalength(@LanguageCode) as varbinary) + cast(@LanguageCode as varbinary);
set context_info @binvar;
declare @buffer varbinary(128) = context_info();
declare @RecoveredLanguageCode nvarchar(6) = cast(substring(@buffer, 5, cast(substring(@buffer, 1, 4) as int)) as nvarchar(6));
select @RecoveredLanguageCode, len(@RecoveredLanguageCode);
答案 1 :(得分:2)
常规varbinary(128)将是完全可投射的。
DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY);
SELECT CAST(@binvar AS NVARCHAR(6));
这会返回初始值'en'。
现在,当您设置上下文值并将其检索回来时,它似乎已变为二进制(128)值而不是varbinary(128)。
SET context_info @binvar;
SELECT CAST(context_info() AS NVARCHAR(6));
现在你有char(0)个字符。
当您将context_info()值转换为varbinary并将其强制转换为nvarchar时,当您明确将ansi padding设置为off时,问题就解决了。
SET ANSI_PADDING OFF;
--
DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;
SET ANSI_PADDING ON;
DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
--> having trailing char(0)
SELECT CAST(@binvar2 AS NVARCHAR(6));
GO
DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;
SET ANSI_PADDING OFF;
DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
--> no more trailing char(0)
SELECT CAST(@binvar2 AS NVARCHAR(6));