Чудной. Копировать в SQL-столбцы с пробелами в именах столбцов
Мне удалось что-то запустить и запустить сегодня в виде небольшого проекта sandbox/POC, но, похоже, я столкнулся с одной проблемой...
Вопрос:
Есть ли способ заставить dapper сопоставлять имена столбцов SQL с пробелами в них.
У меня есть что-то в этом роде, так как мой результирующий набор.
Например:
SELECT 001 AS [Col 1],
901 AS [Col 2],
00454345345345435349 AS [Col 3],
03453453453454353458 AS [Col 4]
FROM [Some Schema].[Some Table]
И мой класс будет выглядеть следующим образом
public class ClassA
{
public string Col1 { get; set; }
public string Col2 { get; set; }
///... etc
}
Моя реализация выглядит в данный момент
public Tuple<IList<TClass>, IList<TClass2>> QueryMultiple<TClass, TClass2>(object parameters)
{
List<TClass> output1;
List<TClass2> output2;
using (var data = this.Connection.QueryMultiple(this.GlobalParameter.RpcProcedureName, parameters, CommandType.StoredProcedure))
{
output1 = data.Read<TClass>().ToList();
output2 = data.Read<TClass2>().ToList();
}
var result = new Tuple<IList<TClass>, IList<TClass2>>(output1, output2);
return result;
}
Примечание. Значение SQL не может быть изменено каким-либо образом.
В настоящее время я просматриваю код dapper, и моим единственным предсказуемым решением является добавление некоторого кода, чтобы "убедить" сравнение столбцов, но пока не так много удачи.
Я видел в StackOverflow, что есть такие вещи, как расширения dapper, но я надеюсь, что смогу это сделать без добавления расширения, если нет. Я возьму все, что быстрее реализовать.
Ответы
Ответ 1
Один из вариантов здесь - перейти через динамический/не общий API, а затем извлечь значения через API IDictionary<string,object>
для каждой строки, но это может быть немного утомительно.
В качестве альтернативы вы можете создать настраиваемый картограф и рассказать о нем; например:
SqlMapper.SetTypeMap(typeof(ClassA), new RemoveSpacesMap());
с:
class RemoveSpacesMap : Dapper.SqlMapper.ITypeMap
{
System.Reflection.ConstructorInfo SqlMapper.ITypeMap.FindConstructor(string[] names, Type[] types)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetConstructorParameter(System.Reflection.ConstructorInfo constructor, string columnName)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetMember(string columnName)
{
var prop = typeof(ClassA).GetProperty(columnName.Replace(" ", ""));
return prop == null ? null : new PropertyMemberMap(columnName, prop);
}
class PropertyMemberMap : Dapper.SqlMapper.IMemberMap
{
private string columnName;
private PropertyInfo property;
public PropertyMemberMap(string columnName, PropertyInfo property)
{
this.columnName = columnName;
this.property = property;
}
string SqlMapper.IMemberMap.ColumnName
{
get { throw new NotImplementedException(); }
}
System.Reflection.FieldInfo SqlMapper.IMemberMap.Field
{
get { return null; }
}
Type SqlMapper.IMemberMap.MemberType
{
get { return property.PropertyType; }
}
System.Reflection.ParameterInfo SqlMapper.IMemberMap.Parameter
{
get { return null; }
}
System.Reflection.PropertyInfo SqlMapper.IMemberMap.Property
{
get { return property; }
}
}
}
Ответ 2
У меня была аналогичная проблема при попытке получить сопоставленные результаты при вызове процедуры sp_spaceused системы. Код Marc не совсем сработал у меня, поскольку он жаловался на то, что не смог найти конструктор по умолчанию. Я также сделал свою версию обобщенной, чтобы ее теоретически можно было повторно использовать. Это может быть не самый быстрый исполняемый фрагмент кода, но он работает для меня, и в нашей ситуации эти вызовы выполняются нечасто.
class TitleCaseMap<T> : SqlMapper.ITypeMap where T: new()
{
ConstructorInfo SqlMapper.ITypeMap.FindConstructor(string[] names, Type[] types)
{
return typeof(T).GetConstructor(Type.EmptyTypes);
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetConstructorParameter(ConstructorInfo constructor, string columnName)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetMember(string columnName)
{
string reformattedColumnName = string.Empty;
foreach (string word in columnName.Replace("_", " ").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
reformattedColumnName += char.ToUpper(word[0]) + word.Substring(1).ToLower();
}
var prop = typeof(T).GetProperty(reformattedColumnName);
return prop == null ? null : new PropertyMemberMap(prop);
}
class PropertyMemberMap : SqlMapper.IMemberMap
{
private readonly PropertyInfo _property;
public PropertyMemberMap(PropertyInfo property)
{
_property = property;
}
string SqlMapper.IMemberMap.ColumnName
{
get { throw new NotImplementedException(); }
}
FieldInfo SqlMapper.IMemberMap.Field
{
get { return null; }
}
Type SqlMapper.IMemberMap.MemberType
{
get { return _property.PropertyType; }
}
ParameterInfo SqlMapper.IMemberMap.Parameter
{
get { return null; }
}
PropertyInfo SqlMapper.IMemberMap.Property
{
get { return _property; }
}
}
}
Ответ 3
Существует пакет nuget Dapper.FluentMap, который позволяет добавлять сопоставления имен столбцов (включая пробелы). Он похож на EntityFramework.
// Entity class.
public class Customer
{
public string Name { get; set; }
}
// Mapper class.
public class CustomerMapper : EntityMap<Customer>
{
public CustomerMapper()
{
Map(p => p.Name).ToColumn("Customer Name");
}
}
// Initialise like so -
FluentMapper.Initialize(a => a.AddMap(new CustomerMapper()));
см. https://github.com/henkmollema/Dapper-FluentMap для получения дополнительной информации.