C# 将.NET Guid转换为MongoDB对象ID
如何将.NET GUID转换为MongoDB对象ID(在C#中)。此外,我是否可以将它从ObjectID再次转换回相同的GUID?虽然不是直接的答案,但请记住,没有要求_id是ObjectID,只要求它是唯一的C# 将.NET Guid转换为MongoDB对象ID,c#,mongodb,guid,C#,Mongodb,Guid,如何将.NET GUID转换为MongoDB对象ID(在C#中)。此外,我是否可以将它从ObjectID再次转换回相同的GUID?虽然不是直接的答案,但请记住,没有要求_id是ObjectID,只要求它是唯一的 可以为_id设置任何有效类型,包括嵌入对象或。使用GUID作为_id应该没问题(除非有任何违反唯一性的情况);事实上,ObjectID实际上只是一个自定义GUID。您不能将ObjectID转换为GUID,反之亦然,因为它们是两个不同的东西(不同的大小、算法) 您可以为mongoDb\u
可以为_id设置任何有效类型,包括嵌入对象或。使用GUID作为_id应该没问题(除非有任何违反唯一性的情况);事实上,ObjectID实际上只是一个自定义GUID。您不能将
ObjectID
转换为GUID
,反之亦然,因为它们是两个不同的东西(不同的大小、算法)
您可以为mongoDb\u id
使用任何类型,包括GUID
例如,在官方c#driver中,您应该指定属性[BsonId]
:
[BsonId]
public Guid Id {get;set;}
[BsonId]
public int Id {get;set;}
:
BSON对象ID是一个12字节的值
由4字节的时间戳组成
(自纪元起的秒数),一个3字节
机器id、2字节进程id和
3字节计数器。请注意
时间戳和计数器字段必须为空
存储的big endian与其他
布森。这是因为他们是
逐字节比较,我们想
确保订单基本上是递增的
:
GUID的值表示为
32个字符的十六进制字符串,
比如
{21EC2020-3AEA-1069-A2DD-08002B30309D},
通常存储为128位
整数
仅供参考,您可以将ObjectId转换为Guid
public static Guid AsGuid(this ObjectId oid)
{
var bytes = oid.ToByteArray().Concat(new byte[] { 5, 5, 5, 5 }).ToArray();
Guid gid = new Guid(bytes);
return gid;
}
/// <summary>
/// Only Use to convert a Guid that was once an ObjectId
/// </summary>
public static ObjectId AsObjectId(this Guid gid)
{
var bytes = gid.ToByteArray().Take(12).ToArray();
var oid = new ObjectId(bytes);
return oid;
}
公共静态Guid AsGuid(此ObjectId oid)
{
var bytes=oid.ToByteArray().Concat(新字节[]{5,5,5}).ToArray();
Guid gid=新Guid(字节);
返回gid;
}
///
///仅用于转换曾经是ObjectId的Guid
///
公共静态ObjectId AsObjectId(此Guid gid)
{
var bytes=gid.ToByteArray().Take(12.ToArray();
变量oid=新对象ID(字节);
返回oid;
}
如果您从头开始,可以将您的“Id”成员键入为Guid
,而不是ObjectId
。这是首选,因为这样您的模型就不必引用MongoDB.Bson
,可以说它不再是POCO类了。如果将成员命名为“Id”,甚至不需要[BsonId]
属性,出于上述原因,最好不要这样做
如果您已经无法在POCO类中使用ObjectId
,并且在意识到困难之后,想要更改“Id”(在类中)的类型,但无法更改“u Id”(在数据中)的类型,则可以创建自定义序列化程序:
public class SafeObjectIdSerializer: ObjectIdSerializer
{
public SafeObjectIdSerializer() : base() { }
public override ObjectId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var bsonType = bsonReader.GetCurrentBsonType();
switch (bsonType)
{
case BsonType.Binary: {
var value = bsonReader
.ReadBinaryData()
.AsGuid
.ToString()
.Replace("-", "")
.Substring(0, 24);
return new ObjectId(value);
}
}
return base.Deserialize(context, args);
}
}
public class CustomSerializationProvider : IBsonSerializationProvider
{
public IBsonSerializer GetSerializer(Type type)
{
if (type == typeof(ObjectId))
{
return new SafeObjectIdSerializer();
}
//add other custom serializer mappings here
//to fall back on the default:
return null;
}
}
正如MiddleTommy所提到的,从Guid
到ObjectId
是有损的,但取决于您如何使用该字段,这可能不是问题。上面使用了前24个十六进制字符,并丢弃了剩余的8个。如果您存储的是随机的ObjectId
值,而不是递增整数的ObjectId转换,那么应该可以
如果您还想开始将ObjectId
编写为Guid
,那么混合使用“\u id”类型似乎并没有什么坏处,只要您回到base.Deserialize()
,但我可能错了,这可能取决于您的实现。文档中没有说明这种或那种方式。为此,可以将此重写添加到上述类:
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, ObjectId value)
{
var bsonWriter = context.Writer;
var guidString = value
.ToString()
.Insert(8, "-")
.Insert(13, "-")
.Insert(18, "-")
.Insert(23, "-") + "00000000";
var asGuid = new Guid(guidString);
bsonWriter.WriteBinaryData(new BsonBinaryData(asGuid));
}
要使其成为您的全局反序列化程序,请执行以下操作:
public class SafeObjectIdSerializer: ObjectIdSerializer
{
public SafeObjectIdSerializer() : base() { }
public override ObjectId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var bsonType = bsonReader.GetCurrentBsonType();
switch (bsonType)
{
case BsonType.Binary: {
var value = bsonReader
.ReadBinaryData()
.AsGuid
.ToString()
.Replace("-", "")
.Substring(0, 24);
return new ObjectId(value);
}
}
return base.Deserialize(context, args);
}
}
public class CustomSerializationProvider : IBsonSerializationProvider
{
public IBsonSerializer GetSerializer(Type type)
{
if (type == typeof(ObjectId))
{
return new SafeObjectIdSerializer();
}
//add other custom serializer mappings here
//to fall back on the default:
return null;
}
}
然后它将只被调用一次,比如您的Global.asax应用程序\u Start()
在一般情况下,无法将其转换回,因为GUID有128位,而ObjectId只有96位。转换过程是有损的,因此是不可逆的。我可以将文档的_id设置为GUID,而不使用ObjectId吗?Norris:(免责声明我几乎没有MongoDB经验)我想你可以,Mongo不会抱怨的。我认为选择ObjectId的唯一原因是为了节省空间。另一个问题可能会有所帮助。当我将Guid转换为ObjectId,再将ObjectId转换为Guid时,结果会有所不同。当您将Guid转换为ObjectId时,实际上丢失了数据。上述转换是单向可重复转换。可以从ObjectId转换为Guid,然后再转换回来,但需要进行一些研究。在过去的4年中我一直没有使用ObjectId,所以我不知道对ObjectId类型做了哪些更改,这些更改将需要更改上述代码。您应该编写一些前后转换的测试。我会尝试将ObjectId转换为128位整数,然后转换为Guid,而不是字节数组。