这是一个编码问题:
C#/.Net/CLR 字符串在内部是 UTF-16 编码的字符串。这意味着每个字符至少两个字节。
Sql Server 不同:
char 和 varchar 使用与该列使用的 collation 绑定的代码页将每个字符表示为单个字节
-
nchar 和 nvarchar 使用 Unicode 的 [旧且过时的] UCS-2 编码将每个字符表示为 2 个字节——该编码在 1996 年随着 Unicode 2.0 和 UTF-16 的发布而被弃用。
UTF-16 和 UCS-2 最大的区别在于 UCS-2 只能表示 Unicode BMP(基本多语言平面)内的字符; UTF-16 可以表示任何 Unicode 字符。在 BMP 中,据我了解,UCS-2 和 UTF-16 表示是相同的。
这意味着要计算与 SQL Server 计算的哈希值相同的哈希值,您将必须获得与 SQL Server 所具有的相同的字节表示形式。因为听起来您正在使用char 或varchar 与排序规则SQL_Latin1_General_CP1_CI_AS、per the documentation,所以CP1 部分表示代码页1252,其余部分表示不区分大小写、区分重音。所以...
您可以通过以下方式获取代码页 1252 的编码:
Encoding enc = Encoding.GetEncoding(1252);
使用该信息,并给出此表:
create table dbo.hash_test
(
id int not null identity(1,1) primary key clustered ,
source_text varchar(2000) collate SQL_Latin1_General_CP1_CI_AS not null ,
hash as
( hashbytes( 'SHA1' , source_text ) ) ,
)
go
insert dbo.hash_test ( source_text ) values ( 'the quick brown fox jumped over the lazy dog.' )
insert dbo.hash_test ( source_text ) values ( 'She looked like something that might have occured to Ibsen in one of his less frivolous moments.' )
go
你会得到这个输出
1: the quick brown fox jumped over the lazy dog.
sql: 6039D100 3323D483 47DDFDB5 CE2842DF 758FAB5F
c#: 6039D100 3323D483 47DDFDB5 CE2842DF 758FAB5F
2: She looked like something that might have occured to Ibsen in one of his less frivolous moments.
sql: D92501ED C462E331 B0E129BF 5B4A854E 8DBC490C
c#: D92501ED C462E331 B0E129BF 5B4A854E 8DBC490C
来自这个程序
class Program
{
static byte[] Sha1Hash( string s )
{
SHA1 sha1 = SHA1.Create() ;
Encoding windows1252 = Encoding.GetEncoding(1252) ;
byte[] octets = windows1252.GetBytes(s) ;
byte[] hash = sha1.ComputeHash( octets ) ;
return hash ;
}
static string HashToString( byte[] bytes )
{
StringBuilder sb = new StringBuilder() ;
for ( int i = 0 ; i < bytes.Length ; ++i )
{
byte b = bytes[i] ;
if ( i > 0 && 0 == i % 4 ) sb.Append( ' ' ) ;
sb.AppendFormat( b.ToString("X2") ) ;
}
string s = sb.ToString() ;
return s ;
}
private static DataTable ReadDataFromSqlServer()
{
DataTable dt = new DataTable();
using ( SqlConnection conn = new SqlConnection( "Server=localhost;Database=sandbox;Trusted_Connection=True;"))
using ( SqlCommand cmd = conn.CreateCommand() )
using ( SqlDataAdapter sda = new SqlDataAdapter(cmd) )
{
cmd.CommandText = "select * from dbo.hash_test" ;
cmd.CommandType = CommandType.Text;
conn.Open();
sda.Fill( dt ) ;
conn.Close() ;
}
return dt ;
}
static void Main()
{
DataTable dt = ReadDataFromSqlServer() ;
foreach ( DataRow row in dt.Rows )
{
int id = (int) row[ "id" ] ;
string sourceText = (string) row[ "source_text" ] ;
byte[] sqlServerHash = (byte[]) row[ "hash" ] ;
byte[] myHash = Sha1Hash( sourceText ) ;
Console.WriteLine();
Console.WriteLine( "{0:##0}: {1}" , id , sourceText ) ;
Console.WriteLine( " sql: {0}" , HashToString( sqlServerHash ) ) ;
Console.WriteLine( " c#: {0}" , HashToString( myHash ) ) ;
Debug.Assert( sqlServerHash.SequenceEqual(myHash) ) ;
}
return ;
}
}
简单!