關(guān)于C#生成MongoDB中ObjectId的實(shí)現(xiàn)方法
ObjectId介紹
在MongoDB中,文檔(document)在集合(collection)中的存儲(chǔ)需要一個(gè)唯一的_id字段作為主鍵。這個(gè)_id默認(rèn)使用ObjectId來定義,因?yàn)镺bjectId定義的足夠短小,并盡最大可能的保持唯一性,同時(shí)能被快速的生成。
ObjectId 是一個(gè) 12 Bytes 的 BSON 類型,其包含:
1.4 Bytes 自紀(jì)元時(shí)間開始的秒數(shù)
2.3 Bytes 機(jī)器描述符
3.2 Bytes 進(jìn)程ID
4.3 Bytes 隨機(jī)數(shù)
從定義可以看出,在同一秒內(nèi),在不同的機(jī)器上相同進(jìn)程ID條件下,非常有可能生成相同的ObjectId。
同時(shí)可以根據(jù)定義判斷出,在給定條件下,ObjectId本身即可描述生成的時(shí)間順序
ObjectId的存儲(chǔ)使用Byte數(shù)組,而其展現(xiàn)需將Byte數(shù)組轉(zhuǎn)換成字符串進(jìn)行顯示,所以通常我們看到的ObjectId都類似于:
ObjectId("507f191e810c19729de860ea")
C#定義ObjectId類
View Code
public class ObjectId
{
private string _string;
public ObjectId()
{
}
public ObjectId(string value)
: this(DecodeHex(value))
{
}
internal ObjectId(byte[] value)
{
Value = value;
}
public static ObjectId Empty
{
get { return new ObjectId("000000000000000000000000"); }
}
public byte[] Value { get; private set; }
public static ObjectId NewObjectId()
{
return new ObjectId { Value = ObjectIdGenerator.Generate() };
}
public static bool TryParse(string value, out ObjectId objectId)
{
objectId = Empty;
if (value == null || value.Length != 24)
{
return false;
}
try
{
objectId = new ObjectId(value);
return true;
}
catch (FormatException)
{
return false;
}
}
protected static byte[] DecodeHex(string value)
{
if (string.IsNullOrEmpty(value))
throw new ArgumentNullException("value");
var chars = value.ToCharArray();
var numberChars = chars.Length;
var bytes = new byte[numberChars / 2];
for (var i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(new string(chars, i, 2), 16);
}
return bytes;
}
public override int GetHashCode()
{
return Value != null ? ToString().GetHashCode() : 0;
}
public override string ToString()
{
if (_string == null && Value != null)
{
_string = BitConverter.ToString(Value)
.Replace("-", string.Empty)
.ToLowerInvariant();
}
return _string;
}
public override bool Equals(object obj)
{
var other = obj as ObjectId;
return Equals(other);
}
public bool Equals(ObjectId other)
{
return other != null && ToString() == other.ToString();
}
public static implicit operator string(ObjectId objectId)
{
return objectId == null ? null : objectId.ToString();
}
public static implicit operator ObjectId(string value)
{
return new ObjectId(value);
}
public static bool operator ==(ObjectId left, ObjectId right)
{
if (ReferenceEquals(left, right))
{
return true;
}
if (((object)left == null) || ((object)right == null))
{
return false;
}
return left.Equals(right);
}
public static bool operator !=(ObjectId left, ObjectId right)
{
return !(left == right);
}
}
C#實(shí)現(xiàn)ObjectId的生成器
View Code
internal static class ObjectIdGenerator
{
private static readonly DateTime Epoch =
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private static readonly object _innerLock = new object();
private static int _counter;
private static readonly byte[] _machineHash = GenerateHostHash();
private static readonly byte[] _processId =
BitConverter.GetBytes(GenerateProcessId());
public static byte[] Generate()
{
var oid = new byte[12];
var copyidx = 0;
Array.Copy(BitConverter.GetBytes(GenerateTime()), 0, oid, copyidx, 4);
copyidx += 4;
Array.Copy(_machineHash, 0, oid, copyidx, 3);
copyidx += 3;
Array.Copy(_processId, 0, oid, copyidx, 2);
copyidx += 2;
Array.Copy(BitConverter.GetBytes(GenerateCounter()), 0, oid, copyidx, 3);
return oid;
}
private static int GenerateTime()
{
var now = DateTime.UtcNow;
var nowtime = new DateTime(Epoch.Year, Epoch.Month, Epoch.Day,
now.Hour, now.Minute, now.Second, now.Millisecond);
var diff = nowtime - Epoch;
return Convert.ToInt32(Math.Floor(diff.TotalMilliseconds));
}
private static byte[] GenerateHostHash()
{
using (var md5 = MD5.Create())
{
var host = Dns.GetHostName();
return md5.ComputeHash(Encoding.Default.GetBytes(host));
}
}
private static int GenerateProcessId()
{
var process = Process.GetCurrentProcess();
return process.Id;
}
private static int GenerateCounter()
{
lock (_innerLock)
{
return _counter++;
}
}
}
使用舉例
class Program
{
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Red;
ObjectId emptyOid = ObjectId.Empty;
Console.WriteLine(emptyOid);
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Green;
for (int i = 0; i < 10; i++)
{
ObjectId oid = ObjectId.NewObjectId();
Console.WriteLine(oid);
}
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Blue;
ObjectId existingOid;
ObjectId.TryParse("507f191e810c19729de860ea", out existingOid);
Console.WriteLine(existingOid);
Console.ReadKey();
}
}
- C#簡(jiǎn)單操作MongoDB的步驟全紀(jì)錄
- C#中如何將MongoDB->RunCommand結(jié)果映射到業(yè)務(wù)類的方法總結(jié)
- Mongodb在CSharp里實(shí)現(xiàn)Aggregate實(shí)例
- MongoDB實(shí)現(xiàn)基于關(guān)鍵詞的文章檢索功能(C#版)
- C#中使用1.7版本驅(qū)動(dòng)操作MongoDB簡(jiǎn)單例子
- MongoDB入門教程之C#驅(qū)動(dòng)操作實(shí)例
- C# 對(duì)MongoDB 進(jìn)行增刪改查的簡(jiǎn)單操作實(shí)例
- C#基于Mongo的官方驅(qū)動(dòng)手?jǐn)]一個(gè)Super簡(jiǎn)易版MongoDB-ORM框架
相關(guān)文章
Avalonia封裝實(shí)現(xiàn)指定組件允許拖動(dòng)的工具類
這篇文章主要為大家詳細(xì)介紹了Avalonia如何封裝實(shí)現(xiàn)指定組件允許拖動(dòng)的工具類,文中的示例代碼講解詳細(xì),感興趣的小伙伴快跟隨小編一起來學(xué)習(xí)學(xué)習(xí)吧2023-03-03C# ThreadPool之QueueUserWorkItem使用案例詳解
這篇文章主要介紹了C# ThreadPool之QueueUserWorkItem使用案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08C#用遞歸算法實(shí)現(xiàn):一列數(shù)的規(guī)則如下: 1、1、2、3、5、8、13、21、34,求第30位數(shù)是多少
本文主要介紹三種方法,解決面試中常見的問題,求第30位數(shù)是多少的問題,希望能給大家一個(gè)參考。2016-06-06C#類繼承中構(gòu)造函數(shù)的執(zhí)行序列示例詳解
這篇文章主要給大家介紹了關(guān)于C#類繼承中構(gòu)造函數(shù)的執(zhí)行序列的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09c#使用process.start啟動(dòng)程序報(bào)錯(cuò)解決方法
c#使用process.start啟動(dòng)程序報(bào)錯(cuò)解決方法,大家參考使用吧2013-12-12