2013-10-29 242 views
7

我是新来的在C#中使用mongo数据库,但我想在mongo数据库中导入大型数据库。 MyDb包含仅具有简单参数Id,Body,Title Tags的实体。mongodb C#异常无法反序列化BsonType字符串Int32

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

    } 

这是我的主要方法的代码

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? 我需要做什么来读取所有数据库?

回答

19

是的,String C#对象中的属性在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; } 

而且我发现非常类似的问题: Deserializing field when type is changed using MongoDb csharp driver


2)第二种方法 - 是'正常化'存储中的数据:将所有整数字段值转换为字符串。因此,您应该将字段$type从16(32位整数)更改为2(字符串)。见BSON types。让我们做它body领域:

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

非常感谢你的回复! – Konrad

+1

不客气。另见第二种方法,也许它会更好。 – Shad

+0

太棒了。方法2是我的首选方法。谢谢! –

0

这将在C#中蒙戈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; } 
}