转换修改后的guid

时间:2012-02-09 18:50:33

标签: c# tsql

我有以下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);
        }
    }

2 个答案:

答案 0 :(得分:2)

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

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

你的sql代码要求sql引擎获取日期时间的内部表示 - 也就是8个字节 - 扔掉两个,然后给出结果。

所以:

  1. 如果您想要相同的值,则需要停止依赖日期时间的存储/序列化方式。使用可以在.net和tsql
  2. 中编写的可重复方法将其转换为6个字节
  3. 意识到你正在删除代表空间独特部分的guid的6个字节,并用时间替​​换它们。因此,您创建的GUID具有两次编码时间,并且极大地增加了创建重复GUID的几率。
  4. 当然,这忽略了一个更明显的问题:“为什么有人想这样做?”我将假设它是一个非常出色的子系统,而不是更有可能的解释,有人正拼命试图解决错误的问题。

答案 1 :(得分:0)

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

使用单个函数替换键的生成比这更有意义。