Dapper. Carte de Colonne SQL avec des espaces dans les noms de colonne
j'ai réussi à faire démarrer quelque chose aujourd'hui sous le nom de small sandbox/POC project, mais j'ai semblé me cogner la tête sur une question...
Question:
y a-t-il un moyen d'amener dapper à mapper les noms de colonnes SQL avec des espaces dedans.
j'ai quelque chose à cet effet comme mon jeu de résultats.
Par exemple:
SELECT 001 AS [Col 1],
901 AS [Col 2],
00454345345345435349 AS [Col 3],
03453453453454353458 AS [Col 4]
FROM [Some Schema].[Some Table]
et ma classe ressemblerait à ce
public class ClassA
{
public string Col1 { get; set; }
public string Col2 { get; set; }
///... etc
}
Mon application ressemble à ça pour le moment
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;
}
Note: le SQL ne peut pas être modifié de quelque manière que ce soit.
actuellement je suis en train de parcourir le code dapper, et ma seule solution prévisible est d'ajouter du code pour "persuader" la comparaison de colonne, mais n'ayant pas beaucoup de chance jusqu'à présent.
j'ai vu sur StackOverflow qu'il y a des choses comme des extensions dapper, mais j'espère que je peux le faire sans ajouter l'extension, si ce n'. Je prendrai ce qui est le plus rapide à mettre en œuvre.
3 réponses
une option ici serait d'aller via L'API dynamique / non-generic, puis de récupérer les valeurs via le IDictionary<string,object>
API par ligne, mais cela pourrait être un peu fastidieux.
comme alternative, vous pouvez créer un mapper personnalisé, et en parler à dapper; par exemple:
SqlMapper.SetTypeMap(typeof(ClassA), new RemoveSpacesMap());
avec:
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; }
}
}
}
Il y a un paquet nuget Dapper.FluentMap qui vous permet d'ajouter le nom de colonne mappings (y compris les espaces). Il est similaire à la 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()));
voir https://github.com/henkmollema/Dapper-FluentMap pour plus.
j'ai eu un problème similaire en essayant d'obtenir des résultats mappés d'un appel à la procédure sp_spaceused du système. Le code de Marc ne fonctionnait pas vraiment pour moi car il se plaignait de ne pas pouvoir trouver un constructeur par défaut. J'ai aussi fait ma version générique pour qu'elle puisse théoriquement être réutilisée. Ce n'est peut-être pas le code le plus performant, mais ça marche pour moi et dans notre situation, ces appels sont rares.
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; }
}
}
}