将.NET Guid转换为MongoDB ObjectID

时间:2011-04-01 13:32:33

标签: c# mongodb guid

如何将.NET GUID转换为MongoDB ObjectID(在C#中)。另外,我可以将它再次转换回ObjectID中的相同GUID吗?

4 个答案:

答案 0 :(得分:32)

您无法将ObjectId转换为GUID,反之亦然,因为它们是两种不同的东西(不同的大小,算法)。

您可以使用mongoDb _id的任何类型,包括GUID

例如,在官方c#驱动程序中,您应指定属性[BsonId]

[BsonId]
public Guid Id {get;set;}

[BsonId]
public int Id {get;set;}

ObjectId

  

BSON ObjectID是12字节的值   由4字节时间戳组成   (自纪元以来的秒数),一个3字节   machine id,一个2字节的进程id和a   3字节计数器。请注意   时间戳和计数器字段必须是   与其余的不同,存储大端   BSON。这是因为他们是   逐字节比较,我们想要   确保大多增加订单。

GUID

  

GUID的值表示为   一个32个字符的十六进制字符串,   如   {21EC2020-3AEA-1069-A2DD-08002B30309D},   并且通常存储为128位   整数

答案 1 :(得分:6)

仅供参考您可以从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;
    }

答案 2 :(得分:3)

虽然没有一个直接的答案,但请记住,没有。要求_id是一个ObjectID ---只有它是唯一的。

可以为_I'd设置任何有效类型,包括嵌入对象或。你应该没事(禁止任何唯一性违规)使用_ID的GUID;实际上,ObjectID实际上只是一个自定义GUID。

答案 3 :(得分:0)

如果要从头开始,则可以将“ Id”成员键入为Guid而不是ObjectId。这是首选,因为这样您的模型就不必引用MongoDB.Bson,可以说不再使它成为POCO类。如果您将成员命名为“ Id”,则甚至不需要[BsonId]属性,最好不要因为上述原因。

如果您已经在POCO类中使用ObjectId并已经意识到了困难,则想更改“ Id”的类型(在您的类中),但无法更改(在您的数据中)“ _ 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);
    }
}

正如MiddleTommy所说,从GuidObjectId是有损耗的,但是取决于您使用该字段的方式,这可能不是问题。上面的代码使用前24个十六进制字符,并丢弃其余的8个字符。如果您存储的是随机ObjectId值,而不是说一个用Int递增的ObjectId转换,那么应该没事。

如果您还想将ObjectId编写为Guid,则只要使用{{1} },但我可能错了,这可能取决于您的实现。该文档没有说任何一种方法。为此,您可以将此替代添加到上面的类中:

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));
    }

然后在只能调用一次的地方,例如您的Global.asax 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; } }

Application_Start()