转换修改了guid
本文关键字:guid 修改 转换 | 更新日期: 2023-09-27 18:24:01
我有下面的t-sql代码,我已经将其转换为c#。
DECLARE @guidRegular UNIQUEIDENTIFIER, @dtmNow DATETIME
SELECT @guidRegular = '{5bf8e554-8dbc-4008-9d48-5c6e0a4d28d7}'
SELECT @dtmNow = '2012-02-09 18:31:38'
print (CAST(CAST(@guidRegular AS BINARY(10)) + CAST(@dtmNow AS BINARY(6)) AS UNIQUEIDENTIFIER))
当我执行.net版本的代码(使用相同的Guid和DateTime)时,我会得到不同的Guid吗?它似乎与datetime元素有关,有人能帮忙吗?
c#扩展码:
using system.data.linq;
...
...
public static class GuidExtensions
{
public static Guid ToNewModifiedGuid(this Guid guid)
{
var dateTime = new DateTime(2012,02,09,18,31,38);
var guidBinary = new Binary(guid.ToByteArray().Take(10).ToArray());
var dateBinary = new Binary(BitConverter.GetBytes(dateTime.ToBinary()).ToArray().Take(6).ToArray());
var bytes = new byte[guidBinary.Length + dateBinary.Length];
Buffer.BlockCopy(guidBinary.ToArray(), 0, bytes, 0, guidBinary.ToArray().Length);
Buffer.BlockCopy(dateBinary.ToArray(), 0, bytes, guidBinary.ToArray().Length, dateBinary.ToArray().Length);
return new Guid(bytes);
}
}
SQL和.net会有不同的日期/时间二进制表示形式,我对此并不感到惊讶。如果他们有,我会很惊讶的。
您的c#代码要求DateTime结构将一个值序列化为64位(8字节)字节数组,该数组可用于重新创建相同的值。然后你扔掉了2个字节(年?毫秒?校验和?谁知道呢?)
您的sql代码要求sql引擎获取日期时间的内部表示形式(也是8个字节),去掉两个,然后给出结果。
因此:
- 如果您想要相同的值,则需要停止依赖于日期时间的存储/序列化方式。使用可以在.net和tsql中编写的可重复方法将其转换为6个字节
- 要意识到,您正在删除表示空间唯一部分的guid的6个字节,并将它们替换为时间。因此,您正在创建一个时间编码两次的GUID,并且大大增加了创建重复GUID的几率
当然,这忽略了一个更突出的问题,即"为什么有人想这么做?"我认为这是一个非常出色的子系统,而不是更可能的解释,即有人拼命想解决错误的问题。
原文章的逻辑有缺陷。作者描述了Natural和Surrogate密钥,但没有认识到UUID的RFC可以用于创建Natural密钥。当然,这样做需要创建一个自定义函数,用于根据一些解决方案域信息生成UUID,而不是依赖默认的基于机器/时间的函数来生成UUID。
不过,用一个函数来代替密钥的生成比这更有意义。