youngfan007 发表于 2015-7-5 13:40:39

C# 生成 MongoDB 中的 ObjectId

ObjectId介绍
  在MongoDB中,文档(document)在集合(collection)中的存储需要一个唯一的_id字段作为主键。这个_id默认使用ObjectId来定义,因为ObjectId定义的足够短小,并尽最大可能的保持唯一性,同时能被快速的生成。
  ObjectId 是一个 12 Bytes 的 BSON 类型,其包含:


[*]4 Bytes 自纪元时间开始的秒数
[*]3 Bytes 机器描述符
[*]2 Bytes 进程ID
[*]3 Bytes 随机数
  从定义可以看出,在同一秒内,在不同的机器上相同进程ID条件下,非常有可能生成相同的ObjectId。
同时可以根据定义判断出,在给定条件下,ObjectId本身即可描述生成的时间顺序
  ObjectId的存储使用Byte数组,而其展现需将Byte数组转换成字符串进行显示,所以通常我们看到的ObjectId都类似于:

  ObjectId("507f191e810c19729de860ea")


C#定义ObjectId类


View Code


1   public class ObjectId
2   {
3   private string _string;
4
5   public ObjectId()
6   {
7   }
8
9   public ObjectId(string value)
10       : this(DecodeHex(value))
11   {
12   }
13
14   internal ObjectId(byte[] value)
15   {
16       Value = value;
17   }
18
19   public static ObjectId Empty
20   {
21       get { return new ObjectId("000000000000000000000000"); }
22   }
23
24   public byte[] Value { get; private set; }
25
26   public static ObjectId NewObjectId()
27   {
28       return new ObjectId { Value = ObjectIdGenerator.Generate() };
29   }
30
31   public static bool TryParse(string value, out ObjectId objectId)
32   {
33       objectId = Empty;
34       if (value == null || value.Length != 24)
35       {
36         return false;
37       }
38
39       try
40       {
41         objectId = new ObjectId(value);
42         return true;
43       }
44       catch (FormatException)
45       {
46         return false;
47       }
48   }
49
50   protected static byte[] DecodeHex(string value)
51   {
52       if (string.IsNullOrEmpty(value))
53         throw new ArgumentNullException("value");
54
55       var chars = value.ToCharArray();
56       var numberChars = chars.Length;
57       var bytes = new byte;
58
59       for (var i = 0; i < numberChars; i += 2)
60       {
61         bytes = Convert.ToByte(new string(chars, i, 2), 16);
62       }
63
64       return bytes;
65   }
66
67   public override int GetHashCode()
68   {
69       return Value != null ? ToString().GetHashCode() : 0;
70   }
71
72   public override string ToString()
73   {
74       if (_string == null && Value != null)
75       {
76         _string = BitConverter.ToString(Value)
77         .Replace("-", string.Empty)
78         .ToLowerInvariant();
79       }
80
81       return _string;
82   }
83
84   public override bool Equals(object obj)
85   {
86       var other = obj as ObjectId;
87       return Equals(other);
88   }
89
90   public bool Equals(ObjectId other)
91   {
92       return other != null && ToString() == other.ToString();
93   }
94
95   public static implicit operator string(ObjectId objectId)
96   {
97       return objectId == null ? null : objectId.ToString();
98   }
99
100   public static implicit operator ObjectId(string value)
101   {
102       return new ObjectId(value);
103   }
104
105   public static bool operator ==(ObjectId left, ObjectId right)
106   {
107       if (ReferenceEquals(left, right))
108       {
109         return true;
110       }
111
112       if (((object)left == null) || ((object)right == null))
113       {
114         return false;
115       }
116
117       return left.Equals(right);
118   }
119
120   public static bool operator !=(ObjectId left, ObjectId right)
121   {
122       return !(left == right);
123   }
124   }
C#实现ObjectId的生成器


View Code


1   internal static class ObjectIdGenerator
2   {
3   private static readonly DateTime Epoch =
4       new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
5   private static readonly object _innerLock = new object();
6   private static int _counter;
7   private static readonly byte[] _machineHash = GenerateHostHash();
8   private static readonly byte[] _processId =
9       BitConverter.GetBytes(GenerateProcessId());
10
11   public static byte[] Generate()
12   {
13       var oid = new byte;
14       var copyidx = 0;
15
16       Array.Copy(BitConverter.GetBytes(GenerateTime()), 0, oid, copyidx, 4);
17       copyidx += 4;
18
19       Array.Copy(_machineHash, 0, oid, copyidx, 3);
20       copyidx += 3;
21
22       Array.Copy(_processId, 0, oid, copyidx, 2);
23       copyidx += 2;
24
25       Array.Copy(BitConverter.GetBytes(GenerateCounter()), 0, oid, copyidx, 3);
26
27       return oid;
28   }
29
30   private static int GenerateTime()
31   {
32       var now = DateTime.UtcNow;
33       var nowtime = new DateTime(Epoch.Year, Epoch.Month, Epoch.Day,
34         now.Hour, now.Minute, now.Second, now.Millisecond);
35       var diff = nowtime - Epoch;
36       return Convert.ToInt32(Math.Floor(diff.TotalMilliseconds));
37   }
38
39   private static byte[] GenerateHostHash()
40   {
41       using (var md5 = MD5.Create())
42       {
43         var host = Dns.GetHostName();
44         return md5.ComputeHash(Encoding.Default.GetBytes(host));
45       }
46   }
47
48   private static int GenerateProcessId()
49   {
50       var process = Process.GetCurrentProcess();
51       return process.Id;
52   }
53
54   private static int GenerateCounter()
55   {
56       lock (_innerLock)
57       {
58         return _counter++;
59       }
60   }
61   }
使用举例



1   class Program
2   {
3   static void Main(string[] args)
4   {
5       Console.ForegroundColor = ConsoleColor.Red;
6
7       ObjectId emptyOid = ObjectId.Empty;
8       Console.WriteLine(emptyOid);
9
10       Console.WriteLine();
11       Console.ForegroundColor = ConsoleColor.Green;
12
13       for (int i = 0; i < 10; i++)
14       {
15         ObjectId oid = ObjectId.NewObjectId();
16         Console.WriteLine(oid);
17       }
18
19       Console.WriteLine();
20       Console.ForegroundColor = ConsoleColor.Blue;
21
22       ObjectId existingOid;
23       ObjectId.TryParse("507f191e810c19729de860ea", out existingOid);
24       Console.WriteLine(existingOid);
25
26       Console.ReadKey();
27   }
28   }
页: [1]
查看完整版本: C# 生成 MongoDB 中的 ObjectId