在表格中,我有一列URL
,我用它来保存网址。我正在使用公式(CONVERT([varbinary](20),hashbytes('SHA1',[URL]))
)计算另一列中的哈希值。它工作正常。
现在我需要在C#中获得类似的函数来获取哈希值,以便在插入新行之前我可以比较并检查类似的行是否存在。我尝试了几个链接,但没有运气。
以下是链接:
How do I calculate the equivalent to SQL Server (hashbytes('SHA1',[ColumnName])) in C#?
** I found this link working. All I need to do is change formula in the db. but is it possible to make it in one line
**
http://forums.asp.net/t/1782626.aspx
DECLARE @HashThis nvarchar(4000);
DECLARE @BinHash varbinary(4000);
SELECT @HashThis = CONVERT(nvarchar(4000),'Password@Test');
SELECT @BinHash = HashBytes('SHA1', @HashThis);
SELECT cast(N'' as xml).value('xs:base64Binary(xs:hexBinary(sql:variable("@BinHash")))', 'nvarchar(4000)');
在c#
中string pwd = "Password@Test";
var sha1Provider = HashAlgorithm.Create("SHA1");
var binHash = sha1Provider.ComputeHash(Encoding.Unicode.GetBytes(pwd));
Console.WriteLine(Convert.ToBase64String(binHash));
我正在使用sql server 2012.数据库的归类是SQL_Latin1_General_CP1_CI_AS
由于
Paraminder
答案 0 :(得分:4)
这是一个编码问题:
C#/.Net / CLR字符串在内部是UTF-16编码的字符串。这意味着每个字符至少两个字节。
Sql Server不同:
char
和varchar
使用与该列使用的collation
相关联的代码页将每个字符表示为单个字节
nchar
和nvarchar
使用[旧的和过时的] UCS-2 Unicode编码将每个字符表示为2个字节 - 这在1996年随着Unicode 2.0的发布而被弃用, UTF-16。
UTF-16和UCS-2之间的最大区别在于UCS-2只能表示Unicode BMP(Basic Multilingual Plane)中的字符; 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 ;
}
}
容易!
答案 1 :(得分:0)
我建议任何时候创建一个哈希,它可以在一个地方完成。无论是在代码中还是在数据库中。从长远来看,它将使您的生活更轻松。这意味着要么在插入记录之前更改C#代码以创建哈希,要么在存储过程中执行重复检查。
无论如何,应该同步复制检查和插入,以便在检查任何重复项和实际插入记录之间不会发生其他插入。最简单的方法是在同一事务中执行它们。
如果你坚持按原样保留逻辑,那么我建议你在数据库中创建哈希,但是通过存储过程或用户定义的函数公开它,可以从你的C#代码中调用它。