簡體   English   中英

mongodb C#異常無法從BsonType Int32反序列化字符串

[英]mongodb C# exception Cannot deserialize string from BsonType Int32

我是在 C# 中使用 mongo db 的新手,但我正在嘗試在 mongo db 中導入大型數據庫。 MyDb 由僅具有簡單參數 Id 、 Body 、 Title Tags 的實體組成。

這是 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 而另一個對象中的相同屬性是 string ? 我必須做什么才能讀取所有數據庫?

是的,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);
});

這將適用於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; }
}

我嘗試了上面的例子,但看起來有些類結構已經改變了。 我有一個名為BuildingNumber的JSON字段,其中大部分時間都有數字,但在Flats或Cottages的情況下,它留空。 代碼低於其正常工作

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

從理論上講,您可以將字符串更改為對象,然后您就可以反序列化 int 以及字符串。 所以如果你有

在 DB 中標記為 int,此構造將對其進行反序列化,然后您可以根據需要對其進行轉換。

[BsonElement("Tags")]
public object Tags { get; set; }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM