Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InvalidCastException for DeserializeDictionary when Key is of type Guid #546

Open
prajaybasu opened this issue Mar 23, 2017 · 11 comments · May be fixed by #2568
Open

InvalidCastException for DeserializeDictionary when Key is of type Guid #546

prajaybasu opened this issue Mar 23, 2017 · 11 comments · May be fixed by #2568
Labels

Comments

@prajaybasu
Copy link

prajaybasu commented Mar 23, 2017

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 prajaybasu changed the title InvalidCastException for DeserializeDictionary InvalidCastException for DeserializeDictionary when Key is of type Guid Mar 23, 2017
@mbdavid
Copy link
Collaborator

mbdavid commented Mar 23, 2017

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<...>(...)

@prajaybasu
Copy link
Author

prajaybasu commented Mar 23, 2017

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)

@xied75
Copy link
Contributor

xied75 commented Mar 24, 2017

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

@bluekuen
Copy link

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

@PassiveModding
Copy link

PassiveModding commented Oct 21, 2019

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
Copy link

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.

@lbnascimento
Copy link
Contributor

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!

@omfgicbf
Copy link

omfgicbf commented Feb 6, 2020

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

@mbdavid
Copy link
Collaborator

mbdavid commented Feb 6, 2020

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)

@Joy-less
Copy link
Collaborator

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

@Joy-less Joy-less reopened this Nov 22, 2024
@Joy-less Joy-less linked a pull request Nov 22, 2024 that will close this issue
@Joy-less
Copy link
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants