mongodb C# 异常无法从 BsonType Int32 反序列化字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19664394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
mongodb C# exception Cannot deserialize string from BsonType Int32
提问by Konrad
I am new to using mongo db in C# , but I am trying to import large database in mongo db. MyDb consists entities having only simple parameters Id , Body , Title Tags.
我是在 C# 中使用 mongo db 的新手,但我正在尝试在 mongo db 中导入大型数据库。MyDb 由只有简单参数 Id 、 Body 、 Title Tags 的实体组成。
This is example of entity in mongo.
这是 mongo 中的实体示例。
{
"Id" : "someff asdsa",
"Title" : "fsfds fds",
"Body ": "fsdfsd fs",
"Tags" : "fsdfdsfsd"
}
This is my class of mongoEntity in C#
这是我在 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);
}
}
This is my code in Main method
这是我在 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();
}
When i run this code I am able to see some data, but I'v got exception "Cannot deserialize string from BsonType Int32." I think that one of property is represented in database as int , but I dont know how to deal with it ? How come one property in one entity is int and the same property in another object is string ? What I have to do to read all database ?
当我运行此代码时,我能够看到一些数据,但出现异常“无法从 BsonType Int32 反序列化字符串”。我认为其中一个属性在数据库中表示为 int ,但我不知道如何处理?为什么一个实体中的一个属性是 int 而另一个对象中的相同属性是 string ?我必须做什么才能读取所有数据库?
采纳答案by Shad
Yes, String
property in C# object has Int32
value in mongo storage, so you have exception during serialization (see code for MongoDB.Bson.Serialization.Serializers.BsonStringSerializer
class).
是的,String
C# 对象中的属性在Int32
mongo 存储中具有值,因此在序列化期间您有异常(请参阅MongoDB.Bson.Serialization.Serializers.BsonStringSerializer
类代码)。
1)You can define your own serializer, which will deserialize Int32
values to string property as well as String
ones. Here it is:
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();
}
}
}
Then mark necessary properties (which have different types in MongoDB in your opinion) with this serializer, for example:
然后用这个序列化器标记必要的属性(在你看来,它们在 MongoDB 中有不同的类型),例如:
[BsonElement("Body")]
[BsonSerializer(typeof(StringOrInt32Serializer))]
public string Body { get; set; }
Also I've found very similar question here: Deserializing field when type is changed using MongoDb csharp driver
另外我在这里发现了非常相似的问题:Deserializing field when type is changed using MongoDb csharp driver
2)The second approach - is to 'normalize'your data in storage: convert all integer field values to string. So, you should change field $type
from 16 (32-bit integer) to 2 (string). See BSON types. Let's do it for body
field:
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);
});
回答by David Basarab
This will work in C# Mongo 2.0+
这将适用于 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";
}
}
}
And you can use it like
你可以像这样使用它
public class TestingObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
[BsonSerializer(typeof(TestingObjectTypeSerializer))]
public string TestingObjectType { get; set; }
}
回答by cs981khx
I tried the above example but looks like some class structures have changed. I have a JSON field called BuildingNumber which has number most of the time but in case of Flats or Cottages its left blank. Code is below which is working as expected
我尝试了上面的示例,但看起来某些类结构已更改。我有一个名为 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; }