mongodb C# 异常 无法从 BsonType Int32 反序列化字符串

本文关键字:BsonType Int32 反序列化 字符串 异常 mongodb | 更新日期: 2023-09-27 18:37:15

我是第一次在C#中使用mongo db,但我正在尝试在mongo db中导入大型数据库。MyDb 由只有简单参数 Id 、Body 、标题标签的实体组成。

这是 mongo 中实体的示例。

{
"Id" : "someff asdsa",
"Title" : "fsfds fds",
"Body ": "fsdfsd fs",
"Tags" : "fsdfdsfsd"
}

这是我在 C# 中的 mongoEntity 类

 [BsonIgnoreExtraElements]
    class Element
    {
        [BsonId]
        public ObjectId _id { get; set; }
        [BsonElement("Id")]
        public string Id { get; set; }
        [BsonElement("Title")]
        public string Title { get; set; }
        [BsonElement("Body")]
        public string Body { get; set; }
        [BsonElement("Tags")]
        public string Tags { get; set; }
        public void ShowOnConsole()
        {
            Console.WriteLine(" _id {0} Id {1} Title {2} Body {3} Tags {4} ", _id, Id, Title, Body, Tags);
        }
    }

这是我在 Main 方法中的代码

  const string connectionString = "mongodb://localhost";
            var client = new MongoClient(connectionString);
            MongoServer server = client.GetServer();
            MongoDatabase database = server.GetDatabase("mydb");

            MongoCollection<Element> collection = database.GetCollection<Element>("train");
            Console.WriteLine("Zaimportowano {0} rekordow ", collection.Count());
            MongoCursor<Element> ids = collection.FindAll();   
             foreach (Element entity in ids)
             {
                 entity.ShowOnConsole();
             }

当我运行此代码时,我能够看到一些数据,但是我有异常"无法从 BsonType Int32 反序列化字符串。"我认为其中一个属性在数据库中表示为 int,但我不知道如何处理它?为什么一个实体中的一个属性是 int,而另一个对象中的相同属性是字符串?我必须做什么才能读取所有数据库?

mongodb C# 异常 无法从 BsonType Int32 反序列化字符串

是的,C# 对象中的String属性在 mongo 存储中具有Int32值,因此在序列化过程中会出现异常(请参阅MongoDB.Bson.Serialization.Serializers.BsonStringSerializer类的代码)。

1) 您可以定义自己的序列化程序,它将Int32值反序列化为字符串属性以及String值。在这里:

public sealed class StringOrInt32Serializer : BsonBaseSerializer
{
    public override object Deserialize(BsonReader bsonReader, Type nominalType,
        Type actualType, IBsonSerializationOptions options)
    {
        var bsonType = bsonReader.CurrentBsonType;
        switch (bsonType)
        {
            case BsonType.Null:
                bsonReader.ReadNull();
                return null;
            case BsonType.String:
                return bsonReader.ReadString();
            case BsonType.Int32:
                return bsonReader.ReadInt32().ToString(CultureInfo.InvariantCulture);
            default:
                var message = string.Format("Cannot deserialize BsonString or BsonInt32 from BsonType {0}.", bsonType);
                throw new BsonSerializationException(message);
        }
    }
    public override void Serialize(BsonWriter bsonWriter, Type nominalType,
        object value, IBsonSerializationOptions options)
    {
        if (value != null)
        {
            bsonWriter.WriteString(value.ToString());
        }
        else
        {
            bsonWriter.WriteNull();
        }
    }
}

然后使用此序列化程序标记必要的属性(在您看来,这些属性在MongoDB中具有不同的类型),例如:

[BsonElement("Body")]
[BsonSerializer(typeof(StringOrInt32Serializer))]
public string Body { get; set; }

我也在这里发现了非常相似的问题:使用 MongoDb csharp 驱动程序更改类型时反序列化字段


2) 第二种方法 - 是"规范化"存储中的数据:将所有整数字段值转换为字符串。因此,您应该将字段$type从 16(32 位整数)更改为 2(字符串)。请参阅 BSON 类型。让我们为body字段执行此操作:

db.train.find({ 'body' : { $type : 16 } }).forEach(function (element) {   
  element.body = "" + element.body;  // Convert field to string
  db.train.save(element);
});

我尝试了上面的例子,但看起来一些类结构已经改变。我有一个名为"建筑物编号"的JSON字段,该字段大部分时间都有编号,但在公寓或小屋的情况下,它留空。代码在下面,按预期工作

public class BsonStringNumericSerializer : SerializerBase<string>
{
    public override string Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var bsonType = context.Reader.CurrentBsonType;
        switch (bsonType)
        {
            case BsonType.Null:
                context.Reader.ReadNull();
                return null;
            case BsonType.String:
                return context.Reader.ReadString();
            case BsonType.Int32:
                return context.Reader.ReadInt32().ToString(CultureInfo.InvariantCulture);
            default:
                var message = string.Format($"Custom Cannot deserialize BsonString or BsonInt32 from BsonType {bsonType}");
                throw new BsonSerializationException(message);
        }
    }
    public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, string value)
    {
        if (value != null)
        {
            if (int.TryParse(value, out var result))
            {
                context.Writer.WriteInt32(result);
            }
            else
            {
                context.Writer.WriteString(value);
            }
        }
        else
        {
            context.Writer.WriteNull();
        }
    }
}
[BsonElement("BUILDING_NUMBER")]
[BsonSerializer(typeof(BsonStringNumericSerializer))]
public string BuildingNumberString { get; set; }
这将

在C# Mongo 2.0+中工作

public class TestingObjectTypeSerializer : IBsonSerializer
{
    public Type ValueType { get; } = typeof(string);
    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        if (context.Reader.CurrentBsonType == BsonType.Int32) return GetNumberValue(context);
        return context.Reader.ReadString();
    }
    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        context.Writer.WriteString(value as string);
    }
    private static object GetNumberValue(BsonDeserializationContext context)
    {
        var value = context.Reader.ReadInt32();
        switch (value)
        {
            case 1:
                return "one";
            case 2:
                return "two";
            case 3:
                return "three";
            default:
                return "BadType";
        }
    }
}

你可以像这样使用它

public class TestingObject
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [BsonSerializer(typeof(TestingObjectTypeSerializer))]
    public string TestingObjectType { get; set; }
}
理论上,

您可以将字符串更改为对象,然后您将能够反序列化 int 和字符串。所以如果你有

在数据库中标记为 int,此构造将对其进行反序列化,然后您可以根据需要转换它。

[BsonElement("Tags")]
public object Tags { get; set; }
相关文章: