#c# #json #dictionary #dapper
#c# #json #словарь #dapper
Вопрос:
Мне нужно сохранить словарь в моей таблице с помощью Dapper. Я почерпнул из других сообщений, что мне нужно использовать материал SqlMapper, который теперь доступен в Dapper.
В моем примере здесь у меня есть свойство с именем ExtendedProperties, которое я хочу сериализовать в JSON и поместить в столбец ExtendedProperties моей таблицы. Вот код, который я использую, чтобы попытаться это сделать. Обратите внимание, что этот код работает для гидратации при выходе, но завершается ошибкой при вставке с ошибкой:
Не существует сопоставления из системы типов объектов.Коллекции.Generic.KeyValuePair`2[[System.Строка, mscorlib, версия = 4.0.0.0, Культура = нейтральная, PublicKeyToken=b77a5c561934e089],[System.Объект, mscorlib, версия = 4.0.0.0, Культура = нейтральная, PublicKeyToken=b77a5c561934e089]] к известному собственному типу управляемого поставщика.’.
public class ExtendableObject
{
public ExtendableObject()
{
ExtendedProperties = new Dictionary<string, object>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Dictionary<string, object> ExtendedProperties { get; set; }
private string ExtendedPropertiesJson
{
get
{
return JsonConvert.SerializeObject(ExtendedProperties);
}
set
{
ExtendedProperties = JsonConvert.DeserializeObject<Dictionary<string, object>>(value);
}
}
}
public class ExtendableObjectTypeMap : SqlMapper.ITypeMap
{
private readonly SqlMapper.ITypeMap _original;
public ExtendableObjectTypeMap(SqlMapper.ITypeMap original)
{
_original = original;
}
public ConstructorInfo FindConstructor(string[] names, Type[] types)
{
return _original.FindConstructor(names, types);
}
public SqlMapper.IMemberMap GetConstructorParameter(System.Reflection.ConstructorInfo constructor, string columnName)
{
return _original.GetConstructorParameter(constructor, columnName);
}
public SqlMapper.IMemberMap GetMember(string columnName)
{
if (columnName == "ExtendedProperties")
{
return new ExtendedPropertiesMemberMap();
}
else
{
return _original.GetMember(columnName);
}
}
/// <summary>
/// A mapper that finds a private member to do the serialization and hydration
/// </summary>
public class ExtendedPropertiesMemberMap : SqlMapper.IMemberMap
{
public string ColumnName
{
get { return "ExtendedProperties"; }
}
public FieldInfo Field
{
get { return typeof(ExtendableObject).GetMember("ExtendedPropertiesJson", BindingFlags.Instance | BindingFlags.NonPublic).Single() as FieldInfo; }
}
public Type MemberType
{
get { return typeof(string); }
}
public ParameterInfo Parameter
{
get
{
return null;
}
}
public PropertyInfo Property
{
get { return typeof(ExtendableObject).GetMember("ExtendedPropertiesJson", BindingFlags.Instance | BindingFlags.NonPublic).Single() as PropertyInfo; }
}
}
SqlMapper.SetTypeMap(typeof(ExtendableObject), new ExtendableObjectTypeMap(SqlMapper.GetTypeMap(typeof(ExtendableObject))));
Комментарии:
1. Могу ли я уточнить: вы намерены хранить json в виде строки? Или для сопоставления пар ключ / значение с параметрами? Или?
2. Я сохраняю весь словарь <строка, объект> в виде строки в столбце nvarchar (max) в формате JSON. Это устаревший код, который я конвертирую из NHibernate, который использует пользовательский тип для выполнения этого в настоящее время.
3. В качестве действительно быстрого грязного решения я иногда использую другое свойство для хранения строкового значения значения столбца таблицы, из которого записывается / считывается база данных. Это свойство преобразует список / словарь в методе get в строку, а в наборе обновляет список / словарь всякий раз, когда задается строковое значение.
4. У меня было такое же исключение. Отладка показала, что я на самом деле передавал динамику.