[CSHARP-50] Error in MongoDB.Bson.BsonWriter.TranslateToBsonType() when translating Document fields of type System.Byte Created: 08/Jul/10 Updated: 19/Oct/16 Resolved: 11/Nov/10 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | SAMUS |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Bug | Priority: | Major - P3 |
| Reporter: | Anye Mercy | Assignee: | Sam Corder |
| Resolution: | Done | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Environment: |
VS 2008 / .NET 3.5 |
||
| Description |
|
The method TranslateToBsonType(object obj) in MongoDB.Bson.BsonWriter does not handle objects of type System.Byte, I am trying to convert a business object to a MongoDB document, the object has fields of type Byte on them, and these are choking. I've given some details below but it really looks like all you should need to fix this is to add this line to the TranslateToBsonType() method among all the other type checks: if(type == typeof(Byte)) — My application code: ToDocument() is the extension method described here http://www.highoncoding.com/Articles/680_Implementing_Business_Object_to_Documents_Converter_for_MongoDb.aspx public static Document ToDocument(this object source) { var document = SerializeMember(source) as Document; return document; } private static object SerializeMember(object source) if (!Type.GetTypeCode(source.GetType()).Equals(TypeCode.Object)) // if the object is IEnumerable var enumerable = source as IEnumerable; if (enumerable != null) foreach (var doc in enumerable) { documents.Add(SerializeMember(doc)); } return documents.ToArray(); var properties = source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); var document = new Document(); foreach (var property in properties) { var propertyValue = property.GetValue(source, null); if (propertyValue == null) continue; document.Add(property.Name, SerializeMember(propertyValue)); } return document; Stack trace: , System.Collections.Generic.IEnumerable<MongoDB.Bson.BsonProperty> propertys = {MongoDB.Serialization.Descriptors.ArrayDescriptor.GetProperties}) Line 485 + 0x24 bytes C# MongoDB.dll!MongoDB.Bson.BsonWriter.CalculateSize(object obj = {object[4]} ) Line 349 + 0x17 bytes C# MongoDB.dll!MongoDB.Bson.BsonWriter.CalculateSizeObject(object obj = {MongoDB.Serialization.Descriptors.DocumentPropertyDescriptor} ) Line 464 + 0xe bytes C# ) Line 73 + 0xd bytes C# ) Line 56 + 0xb bytes C# MongoDB.dll!MongoDB.Connections.Connection.SendMessage(MongoDB.Protocol.IRequestMessage message = {MongoDB.Protocol.InsertMessage} , string database = "DocTest1") Line 126 + 0xb bytes C# ) Line 333 + 0x3c bytes C# ) Line 27 + 0xa bytes C# |
| Comments |
| Comment by Steve Wagner [ 11/Nov/10 ] |
|
Can you check if this still happens in our latest master? If yes please report here back https://github.com/mongodb-csharp/mongodb-csharp/issues. |
| Comment by Anye Mercy [ 12/Jul/10 ] |
|
I actually hit another bug when I use the strongly typed version – I suspect it is an artifact of the first bug but it does bring up an interesting point. Basically what is happening is that since currently the Byte can't be translated, that field is being saved to the database as null. When I try to load the Document using the typed GetCollection, it calls (after a fashion) the MemberMapBase to start setting properties. When it comes to the null byte field, it casts it as an object[0] - then calls the setter on the underlying object – but Byte is not a valid Byte so it throws an InvalidCastException. The actual error is thrown in MemberMapBase.SetValue at _setter(instance,value) I thought about this a while trying to decide what the proper behavior should be and it really comes down to whether the MemberMapBase is only used when constructing a new object or whether it can be used on an existing object. If we know that it only is ever used to create objects then I would think the proper behavior would be to skip nulls, leaving the object's properties in the default state. If we don't know this then it is not a good idea to try to skip nulls in the driver because you can't tell the difference between an intentional null and a just-not-populated null that you wouldn't want to replace existing data. PS - Thanks for the quick response! This can be worked around on the client side by making sure the setters all handle nulls more gracefully but for large applications this would be a big detriment to conversion because all the business objects using Bytes or other non-nullable types would be potentially affected. (My application is a production application targeting SQL Server, and I'm working on a proof of concept to see if MongoDB will perform better in our problem space). I also was able to work around it by using the non-typed GetCollection and then using my ToClass<T> to rehydrate the object from the database, this method skipped the nulls. |
| Comment by Steve Wagner [ 09/Jul/10 ] |
|
Ok i am looking at this. By the way. Why do you dont use the much more powerful typed collection in the latest version of the driver? var docTable = db.GetCollection<FullDocumentInfo>("CaseDocuments"); |