2012-04-12 19 views
8

Tôi đang thử nghiệm một số tình huống với MongoDb để xem cách khôi phục từ các vấn đề dữ liệu có thể xảy ra.Trường Deserializing khi loại được thay đổi bằng trình điều khiển csharp MongoDb

Tôi có các lớp học (Địa chỉ có bộ sưu tập Địa chỉ) với thuộc tính zipcode trong Địa chỉ ban đầu được tạo thành chuỗi. Tôi đã lưu nhiều bản ghi Địa chỉ và có thể truy xuất chúng tất cả. như thế này, var allAddresses = addresses.FindAllAs();

Tôi đã thay đổi thuộc tính mã zip thành int và lưu một số bản ghi. Sau đó tôi đã thay đổi thuộc tính mã zip thành chuỗi.

Khi tôi cố đọc lại bộ sưu tập, tôi nhận được một lỗi deserializing, như mong đợi. var allAddresses = addresses.FindAllAs();

Mục tiêu của tôi là có thể ghi đè quá trình deserialization vì vậy nếu xảy ra lỗi deserialization trường tôi có thể chọn bỏ qua hoặc áp dụng giá trị mặc định.

Tôi đã thử một bộ nối tiếp tùy chỉnh không hoạt động. Mọi lơi đê nghị đêu nên được đanh gia cao.

public class MyCustomSerializer : BsonBaseSerializer 
    { 

    public override object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options) 
    { 
     if (bsonReader.CurrentBsonType != BsonType.String) 
     { 
     return string.Empty; 
     } 

     return bsonReader.ReadString(); 
    } 

    public override void Serialize(
       BsonWriter bsonWriter, 
       Type nominalType, 
       object value, 
       IBsonSerializationOptions options) 
    { 
     bsonWriter.WriteStartDocument(); 
     bsonWriter.WriteName("ZipCode"); 
     bsonWriter.WriteString(value.ToString()); 
     bsonWriter.WriteEndDocument(); 
    } 
    } 
+0

nếu một câu trả lời giải quyết vấn đề của bạn, bạn nên chấp nhận câu trả lời. Kiểm tra bên cạnh upvote/downvote –

Trả lời

9

Có một vài điều đang diễn ra. Một trong những chính là bạn phải tiêu thụ đầu vào bất kể loại hoặc quá trình deserialization được ra khỏi đồng bộ. Tôi đã thử nghiệm kịch bản của bạn bằng cách viết một serializer tùy chỉnh được gọi là ZipCodeSerializer mà xử lý nulls và viết ZipCodes như chuỗi, nhưng chấp nhận hoặc chuỗi hoặc ints vào đầu vào và chuyển đổi ints thành chuỗi.

tôi sử dụng lớp này để kiểm tra:

public class Address 
{ 
    public ObjectId Id; 
    public string ZipCode; 
} 

Và đây là serializer tùy chỉnh tôi đã viết:

public class ZipCodeSerializer : 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(); 
      default: 
       var message = string.Format("ZipCodeSerializer expects to find a String or an Int32, not a {0}.", bsonType); 
       throw new BsonSerializationException(message); 
     } 
    } 

    public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options) 
    { 
     if (value == null) 
     { 
      bsonWriter.WriteNull(); 
     } 
     else 
     { 
      bsonWriter.WriteString((string)value); 
     } 
    } 
} 

Bạn phải chắc chắn serializer tùy chỉnh được nối, mà bạn có thể làm như thế này:

BsonClassMap.RegisterClassMap<Address>(cm => 
    { 
     cm.AutoMap(); 
     cm.GetMemberMap(a => a.ZipCode).SetSerializer(new ZipCodeSerializer()); 
    }); 

Vì vậy, bây giờ trường ZipCode của lớp Địa chỉ sẽ được xử lý bởi custo m serializer.

Tôi tạo ra một số dữ liệu thử nghiệm sử dụng BsonDocument để làm cho nó dễ dàng để buộc các phiên bản lưu trữ dữ liệu cụ thể trong bộ sưu tập thử nghiệm của tôi:

collection.Drop(); 
collection.Insert(new BsonDocument()); 
collection.Insert(new BsonDocument("ZipCode", BsonNull.Value)); 
collection.Insert(new BsonDocument("ZipCode", "12345")); 
collection.Insert(new BsonDocument("ZipCode", 56789)); 

Đây là những gì các tài liệu trông giống như sử dụng vỏ Mongo:

> db.test.find() 
{ "_id" : ObjectId("4f871374e447ad238040e346") } 
{ "_id" : ObjectId("4f871374e447ad238040e347"), "ZipCode" : null } 
{ "_id" : ObjectId("4f871374e447ad238040e348"), "ZipCode" : "12345" } 
{ "_id" : ObjectId("4f871374e447ad238040e349"), "ZipCode" : 56789 } 
> 

vì vậy chúng tôi thấy rằng một số ZipCodes là chuỗi và một số là ints (cũng có một null ném vào).

Và đây là mã kiểm tra của tôi:

foreach (var document in collection.FindAll()) 
{ 
    Console.WriteLine(document.ToJson()); 
} 

Và đầu ra của chạy mã kiểm tra là:

{ "_id" : ObjectId("4f871374e447ad238040e346"), "ZipCode" : null } 
{ "_id" : ObjectId("4f871374e447ad238040e347"), "ZipCode" : null } 
{ "_id" : ObjectId("4f871374e447ad238040e348"), "ZipCode" : "12345" } 
{ "_id" : ObjectId("4f871374e447ad238040e349"), "ZipCode" : "56789" } 
Press Enter to continue 

Chú ý rằng mã bưu điện đó là một int trong cơ sở dữ liệu hiện nay là một chuỗi .

Mã nguồn đầy đủ các chương trình thử nghiệm của tôi là có sẵn tại địa chỉ:

http://www.pastie.org/3775465

+1

Tôi nên thêm rằng nó có thể đơn giản hơn rất nhiều để chỉ sửa chữa dữ liệu trong cơ sở dữ liệu để không có các loại hỗn hợp cho Mã Zip nữa! :) –

+0

Cảm ơn, giải pháp này làm việc cho tôi vì tôi không thể cập nhật hàng triệu bản ghi trong cơ sở dữ liệu;) –

Các vấn đề liên quan