Convert .NET Guid to MongoDB ObjectID

让人想犯罪 __ 提交于 2019-12-03 10:48:23

问题


How can I convert a .NET GUID to a MongoDB ObjectID (in C#). Also, can I convert it back again to the same GUID from the ObjectID?


回答1:


You can't convert ObjectId into GUID and vice versa, because they are two different things(different sizes, algoritms).

You can use any type for mongoDb _id including GUID.

For example in official c# driver you should specify attribute [BsonId]:

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

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

ObjectId:

A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure a mostly increasing order.

GUID:

The value of a GUID is represented as a 32-character hexadecimal string, such as {21EC2020-3AEA-1069-A2DD-08002B30309D}, and is usually stored as a 128-bit integer




回答2:


FYI You can convert from an ObjectId to a 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;
    }



回答3:


although not a direct answer keep in mind that there is no.requirement that _id be an ObjectID --- only that it be unique.

any valid type can be set for _I'd including an embedded object or a . you should be fine (barring any uniqueness violations) using a GUID for _id; in fact, ObjectID is really just a custom GUID.




回答4:


If you're starting everything from scratch, you can type your "Id" member as a Guid instead of ObjectId. That's preferred because then your model doesn't have to reference MongoDB.Bson, arguably making it a POCO class no more. You don't even need the [BsonId] attribute if you name the member "Id", and it's better not to for the aforementioned reason.

If you're already stuck using ObjectId in your POCO classes and--having realized the difficulties--would like to change the type of "Id" (in your class), but are not able to change the type of "_id" (in your data), you can make a custom serializer:

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

As MiddleTommy mentioned, going from Guid to ObjectId is lossy, but depending on how you use that field, that may not be a problem. The above uses the first 24 hexadecimal characters and discards the remaining 8. If you're storing random ObjectId values and not say, an ObjectId conversion of incrementing ints, you should be fine.

If you want to also start writing ObjectId as Guid, it doesn't seem to hurt anything to mix "_id" types, as long as you're falling back on base.Deserialize(), but I could be wrong and it could matter depending on your implementation. The documentation doesn't say one way or the other. To do that you can add this override to the above class:

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

To make that your global deserializer:

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

Then somewhere where it will only be called once, like your Global.asax Application_Start()

BsonSerializer.RegisterSerializationProvider(new CustomSerializationProvider());


来源:https://stackoverflow.com/questions/5514111/convert-net-guid-to-mongodb-objectid

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!