转换修改了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);
        }
    }

转换修改了guid

SQL和.net会有不同的日期/时间二进制表示形式,我对此并不感到惊讶。如果他们有,我会很惊讶的。

您的c#代码要求DateTime结构将一个值序列化为64位(8字节)字节数组,该数组可用于重新创建相同的值。然后你扔掉了2个字节(年?毫秒?校验和?谁知道呢?)

您的sql代码要求sql引擎获取日期时间的内部表示形式(也是8个字节),去掉两个,然后给出结果。

因此:

  1. 如果您想要相同的值,则需要停止依赖于日期时间的存储/序列化方式。使用可以在.net和tsql中编写的可重复方法将其转换为6个字节
  2. 要意识到,您正在删除表示空间唯一部分的guid的6个字节,并将它们替换为时间。因此,您正在创建一个时间编码两次的GUID,并且大大增加了创建重复GUID的几率

当然,这忽略了一个更突出的问题,即"为什么有人想这么做?"我认为这是一个非常出色的子系统,而不是更可能的解释,即有人拼命想解决错误的问题。

原文章的逻辑有缺陷。作者描述了Natural和Surrogate密钥,但没有认识到UUID的RFC可以用于创建Natural密钥。当然,这样做需要创建一个自定义函数,用于根据一些解决方案域信息生成UUID,而不是依赖默认的基于机器/时间的函数来生成UUID。

不过,用一个函数来代替密钥的生成比这更有意义。