关于C#生成MongoDB中ObjectId的实现方法
程序员文章站
2023-12-13 21:31:58
objectid介绍在mongodb中,文档(document)在集合(collection)中的存储需要一个唯一的_id字段作为主键。这个_id默认使用objectid来...
objectid介绍
在mongodb中,文档(document)在集合(collection)中的存储需要一个唯一的_id字段作为主键。这个_id默认使用objectid来定义,因为objectid定义的足够短小,并尽最大可能的保持唯一性,同时能被快速的生成。
objectid 是一个 12 bytes 的 bson 类型,其包含:
1.4 bytes 自纪元时间开始的秒数
2.3 bytes 机器描述符
3.2 bytes 进程id
4.3 bytes 随机数
从定义可以看出,在同一秒内,在不同的机器上相同进程id条件下,非常有可能生成相同的objectid。
同时可以根据定义判断出,在给定条件下,objectid本身即可描述生成的时间顺序
objectid的存储使用byte数组,而其展现需将byte数组转换成字符串进行显示,所以通常我们看到的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#实现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();
}
}