设为首页 收藏本站
查看: 1460|回复: 0

[经验分享] C# 生成 MongoDB 中的 ObjectId

[复制链接]

尚未签到

发表于 2015-7-5 13:40:39 | 显示全部楼层 |阅读模式
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类


DSC0000.gif DSC0001.gif 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[numberChars / 2];
58
59       for (var i = 0; i < numberChars; i += 2)
60       {
61         bytes[i / 2] = 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[12];
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   }
DSC0002.png

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-83390-1-1.html 上篇帖子: MongoDB索引 下篇帖子: 高可用的MongoDB集群-实战篇
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表