Open Tasteful opened 9 years ago
Not at all sure if this might work, but have you tried installing the type handler to handle IEnumerable<KeyValuePair<Guid, string>> instead of Dictionary<Guid, string>?
On 21 Dec 2014, at 10:59, Patric Forsgard notifications@github.com wrote:
I have the same issue as the following SO question but the question is missing any answer :(
http://stackoverflow.com/questions/24268378/save-a-dictionary-as-json-in-sql-with-dapper
I'm trying to map a property of type Dictionary<Guid,string> with a ITypeHandler as JSON into a single column in database but will all the time got the following error.
No mapping exists from object type System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] to a known managed provider native type.'. The ITypeHandler that I have tried with are the following.
internal class DictionaryGuidStringTypeHandler : SqlMapper.TypeHandler<Dictionary<Guid, string>> { public override void SetValue(IDbDataParameter parameter, Dictionary<Guid, string> value) { if (value == null) { parameter.Value = DBNull.Value; } else { parameter.Value = Converter.ConvertObjectToJson(value); } }
public override Dictionary<Guid, string> Parse(object value) { var strValue = value as string; if (string.IsNullOrEmpty(strValue)) { return null; } return Converter.ConvertJsonToObject<Dictionary<Guid, string>>(strValue); } } internal class KeyValuePairGuidStringTypeHandler : SqlMapper.TypeHandler<KeyValuePair<Guid, string>> { public override void SetValue(IDbDataParameter parameter, KeyValuePair<Guid, string> value) { if (ReferenceEquals(value, default(KeyValuePair<Guid, string>))) { parameter.Value = DBNull.Value; } else { parameter.Value = Converter.ConvertObjectToJson(value); } } public override KeyValuePair<Guid, string> Parse(object value) { var strValue = value as string; if (string.IsNullOrEmpty(strValue)) { return default(KeyValuePair<Guid, string>); } return Converter.ConvertJsonToObject<KeyValuePair<Guid, string>>(strValue); } } internal class NullableKeyValuePairGuidStringTypeHandler : SqlMapper.TypeHandler<KeyValuePair<Guid, string>?> { public override void SetValue(IDbDataParameter parameter, KeyValuePair<Guid, string>? value) { if (value == null) { parameter.Value = DBNull.Value; } else { parameter.Value = Converter.ConvertObjectToJson(value); } } public override KeyValuePair<Guid, string>? Parse(object value) { var strValue = value as string; if (string.IsNullOrEmpty(strValue)) { return null; } return Converter.ConvertJsonToObject<KeyValuePair<Guid, string>>(strValue); } }
Is it possible to map a single property on the class to a specific type-handler by code or with an attribute? My feeling are that the error originating from the part that creating the data reader to class mapping and if that should be possible to override some of that logic on a easy way I think that will solve my problem.
I can always create a shadow property that will make the conversion inside the class to/from json and expose as a string on the class but I hope I can avoid that.
BR Patric
— Reply to this email directly or view it on GitHub.
@jamesholwell No, that was not working either :(
But found out that its working if I add the input as an instance of SqlMapper.ICustomQueryParameter
that will make the conversion for the input object and then the output will work with the following typehandler.
internal class DictionaryGuidStringTypeHandler : SqlMapper.TypeHandler<Dictionary<Guid, string>>
{
public override void SetValue(IDbDataParameter parameter, Dictionary<Guid, string> value)
{
throw new NotSupportedException("SetValue method is not used, use the JsonQueryParameter as the input to serialize the object to json.");
//if (value == null)
//{
// parameter.Value = DBNull.Value;
//}
//else
//{
// parameter.Value = Converter.ConvertObjectToJson(value);
//}
}
public override Dictionary<Guid, string> Parse(object value)
{
var strValue = value as string;
if (string.IsNullOrEmpty(strValue))
{
return null;
}
return Converter.ConvertJsonToObject<Dictionary<Guid, string>>(strValue);
}
}
The SqlMapper.ICustomQueryParameter is the following.
internal class JsonQueryParameter : SqlMapper.ICustomQueryParameter
{
private readonly object _value;
public JsonQueryParameter(object value)
{
_value = value;
}
public void AddParameter(IDbCommand command, string name)
{
var param = command.CreateParameter();
param.ParameterName = name;
if (_value == null)
param.Value = DBNull.Value;
else
param.Value = Converter.ConvertObjectToJson(_value);
command.Parameters.Add(param);
}
}
If we switch the place of the if-statement:
https://github.com/StackExchange/dapper-dot-net/blob/master/Dapper%20NET40/SqlMapper.cs#L888 and https://github.com/StackExchange/dapper-dot-net/blob/master/Dapper%20NET40/SqlMapper.cs#L893
so we first are checking for ITypehandler
and then checking if the input parameter is IEnumerable
instead of reverse order.
@mgravell Do you remember why you added the typeHandlers
-lookup after the IEnumerable
check when execute the LookupDbType
-method?
Any news on this? I want to do the same thing.
I have the same issue as the following SO question but the question is missing any answer :(
http://stackoverflow.com/questions/24268378/save-a-dictionary-as-json-in-sql-with-dapper
I'm trying to map a property of type
Dictionary<Guid,string>
with aITypeHandler
as JSON into a single column in database but will all the time got the following error.The
ITypeHandler
that I have tried with are the following.Is it possible to map a single property on the class to a specific type-handler by code or with an attribute? My feeling are that the error originating from the part that creating the data reader to class mapping and if that should be possible to override some of that logic on a easy way I think that will solve my problem.
I can always create a shadow property that will make the conversion inside the class to/from json and expose as a string on the class but I hope I can avoid that.
BR Patric