Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将.NET Guid转换为MongoDB对象ID_C#_Mongodb_Guid - Fatal编程技术网

C# 将.NET Guid转换为MongoDB对象ID

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

如何将.NET GUID转换为MongoDB对象ID(在C#中)。此外,我是否可以将它从ObjectID再次转换回相同的GUID?

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


可以为_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,而不是字节数组。