[CSHARP-83] Generic lists, enumerables, etc... are not persisted as bson arrays Created: 22/Oct/10 Updated: 02/Apr/15 Resolved: 01/Nov/10 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | None |
| Affects Version/s: | 0.5 |
| Fix Version/s: | 0.7 |
| Type: | Bug | Priority: | Major - P3 |
| Reporter: | Craig Wilson | Assignee: | Robert Stam |
| Resolution: | Done | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Description |
|
Given a class like this: public class Student public List<int> Scores { get; set; } } Scores is not persisted as a bson array, but rather as a document. I would assume this pertains to any property that is not defined as an array. IEnumerable<T> |
| Comments |
| Comment by Robert Stam [ 01/Nov/10 ] |
|
IEnumerable and IEnumerable<T> values are now serialized as BsonArrays. Added a general mechanism to register generic serializer definitions (see EnumerableSerializer<T> and Lookup- and RegisterGenericSerializerDefinition). |
| Comment by Craig Wilson [ 31/Oct/10 ] |
|
1) Sounds good for not using ArrayList or other. 2) I Like the non-string key versions to be persisted as an array of key value pairs. That makes a lot of sense. All I really need out of this is transparent persistence of collections without requiring types to be placed into the database. |
| Comment by Robert Stam [ 31/Oct/10 ] |
|
Just wondering: why use ArrayList and HashTable at all? Would the following work just as well For IEnumerable use List<object> Also, do we have to restrict T in Dictionary<T,V> to be convertible to and from string? What we could do is: 1. If T is string, serialize dictionary to a BsonDocument So for example, a property P of type Dictionary<K, V> would be serialized as: { ..., P : [[k1, v1], [k2, v2], ...], ... } |
| Comment by Craig Wilson [ 24/Oct/10 ] |
|
While that certainly is an option, I can't think of any benefit for it off the top of my head. If you are using an interface, it means you rely on the interface and it's underlying implementation to provide the functionality necessary. If you need specific functionality delivered only by a specific concrete class, then just declare the property as a concrete class. I personally try and stay away from any form of attributes. It pollutes the class and takes it from being POCO (or POJO for you java folks) and makes it some sort of hybrid. So, as far as mapping goes: property type implementation IEnumerable<T> List<T> HashSet<T> HashSet<T> |
| Comment by Scott Hernandez (Inactive) [ 24/Oct/10 ] |
|
The way we do this with in morphia (java mapper) is to specify the concrete class via an annotation (or a custom converter): public class Student { In the c# it would probably be something like this with an attribute. |
| Comment by Robert Stam [ 22/Oct/10 ] |
|
I like the way you think. I was hung up on trying to guarantee that the rehydrated object was identical to the original one. But I agree that that's not nearly as important as keeping the data platform neutral. |
| Comment by Craig Wilson [ 22/Oct/10 ] |
|
Before you take that stance, if I have declared a property as IList<int>, the it should imply that I simply don't care about the actual implementation of IList<int> is, just that is supports that interface. In other words, don't serialize the type. When you see an IList<T>, just bring it back in as List<int>. When you see IEnumerable<T> or ICollection<T>, do the same thing. There is no need to persist the type because we only care that whatever is rehydrated supports the interface. Also, placing .NET specific types into the document truly kills cross platform integration. I have some apps that have a backend using mongodb-csharp and a front end using ruby. If I had to instruct my ruby front end that IList[[something]] means whatever, it would be horrible. It's just an array to mongodb. |
| Comment by Robert Stam [ 22/Oct/10 ] |
|
Good point. I think it's a side effect of being able to handle: public class Student { public IList<int> Scores { get; set; } } where the Scores property is declared using an interface type. In this case the document has a discriminator ("_t") to record what concrete class to instantiate when deserializing. I will look into serializing straight into an array when a discriminator is not required. |