LiteDB icon indicating copy to clipboard operation
LiteDB copied to clipboard

InvalidCastException for DeserializeDictionary when Key is of type Guid

Open prajaybasu opened this issue 8 years ago • 11 comments

Stack trace :

System.InvalidCastException: Invalid cast from 'System.String' to 'System.Guid'.
   at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
   at LiteDB.BsonMapper.DeserializeDictionary(Type K, Type T, IDictionary dict, BsonDocument value)
   at LiteDB.BsonMapper.Deserialize(Type type, BsonValue value)
   at LiteDB.BsonMapper.DeserializeObject(Type type, Object obj, BsonDocument value)
   at LiteDB.BsonMapper.Deserialize(Type type, BsonValue value)
   at LiteDB.BsonMapper.ToObject[T](BsonDocument doc)
   at LiteDB.LiteCollection`1.<Find>d__17.MoveNext()

Data Type :

    public class QuizData
    {
        public QuizData()
        { }
        public string RollNumber { get; set; }
        public Dictionary<Guid,Choice> QuestionChoiceList { get; set; }
    }

Method Call :

_db.GetCollection<QuizData>("collectionName").FindAll();

I think it's throwing because Generic conversion doesn't support GUIDs. Platform : ASP.NET Core 1.1.0 on .NET Core 1.1.0 using .NET Core SDK 1.0.0-preview2-1-003177 Edit : I got it working by forking and using a very quick-and-dirty fix in DeserializeDictionary()

Guid temp;
var k = Guid.TryParse(key, out temp) ? 
temp : K.GetTypeInfo().IsEnum ? 
Enum.Parse(K, key) : Convert.ChangeType(key, K);

So basically right now you can't have Guid as a TKey in an IDictionary

prajaybasu avatar Mar 23 '17 07:03 prajaybasu

Hi @prajaybasu, it's not possible use Dictionary with non string TKey because each key must be a valid key in JSON (and must be a string). You can change your Dictionary to a List or you can implement your custom serialization to this Dictionary instance, using BsonMapper.Global.RegisterType<...>(...)

mbdavid avatar Mar 23 '17 10:03 mbdavid

I suppose it does convert other TKey like int to string ? Guid does have ToString(), it's just that Convert.ChangeType doesn't support it, I think it needs a special case. Other deserializers like Newtonsoft support Guid out of the box though - the model works fine with Newtonsoft on the client side, I had to fork to add the special case for Guid in DeserializeDictionary() on the server side and it just works fine for me currently. (SortedDictionary<int,TValue> also works fine)

prajaybasu avatar Mar 23 '17 11:03 prajaybasu

Agree with @prajaybasu here, if some simple modification could expand the usability that would be worth it.

http://stackoverflow.com/questions/393731/generic-conversion-function-doesnt-seem-to-work-with-guids

xied75 avatar Mar 24 '17 23:03 xied75

I've got the same issue... When is this fixed?

bluekuen avatar Jan 17 '19 11:01 bluekuen

Might be better to rename this issue to something like "InvalidCastException for DeserializeDictionary when Key is of non primitive or string type" Since it affects any non string/primitive key for a dictionary

PassiveModding avatar Oct 21 '19 05:10 PassiveModding

as a side note, you could just serialize the key https://github.com/mbdavid/LiteDB/blob/0412d11ed9492bd0e442db3e18b195b164bf5ca9/LiteDB/Client/Mapper/BsonMapper.Serialize.cs#L167 with something such as o[this.Serialize(key.GetType(), key).ToString()] = this.Serialize(type, value, depth);

and then handle the deserialization of keys somehow here https://github.com/mbdavid/LiteDB/blob/f568f133077dc24d2b74fb7b23f1bf64e042706d/LiteDB/Client/Mapper/BsonMapper.Deserialize.cs#L252 I haven't really found a way to deserialize the key from string back into it's class however.

Using Json.NET for this in particular does allow this to work though. var k = K.IsEnum ? Enum.Parse(K, el.Key) : JsonConvert.DeserializeObject(el.Key, K); that on it's own doesn't support Guids due to how LiteDB serializes them. But since this part uses Json.NET you could also serialize the keys using Json.NET o[JsonConvert.SerializeObject(key)] = this.Serialize(type, value, depth); Which then serializes fine from all my testing.

PassiveModding avatar Oct 21 '19 06:10 PassiveModding

Hi! With the objective of organizing our issues, we are closing old unsolved issues. Please check the latest version of LiteDB and open a new issue if your problem/question/suggestion still applies. Thanks!

lbnascimento avatar Feb 05 '20 14:02 lbnascimento

@lbnascimento so you are officially abandoning support for v4 now?

omfgicbf avatar Feb 06 '20 01:02 omfgicbf

Hi @omfgicbf, v4 will be maintained only for bugs and critical updates. Any new feature will be applied only in v5 (it's too hard keep both in evolution)

mbdavid avatar Feb 06 '20 16:02 mbdavid

This issue is due to the fact that BsonDocument only supports string key (and BsonValue value). Really, it should support BsonValue key.

Joy-less avatar Nov 22 '24 01:11 Joy-less

Unfortunately, due to the fact that BufferWriter is hardcoded to write keys as string, BsonDocument can't be changed to support BsonValue keys without a breaking change to LiteDB (a very complicated one too). I suppose it's because of the JSON format. However, keys can still be deserialized from strings. See #2568.

Joy-less avatar Nov 22 '24 02:11 Joy-less

Fixed in https://github.com/litedb-org/LiteDB/pull/2701

JKamsker avatar Oct 05 '25 18:10 JKamsker

Uh...better late than never I guess.

prajaybasu avatar Oct 07 '25 15:10 prajaybasu