2013-02-11 11 views
13

Sono riuscito a ottenere qualcosa di attivo e funzionante oggi come piccolo progetto sandbox/POC, ma sono sembrate a sbattere la testa su una questione ...Dapper. Mappa alla Colonna di SQL con gli spazi nei nomi delle colonne

Domanda:

C'è un modo per ottenere dapper mappare i nomi delle colonne SQL con spazi al loro interno.

Ho qualcosa in questo senso come il mio set di risultati.

Ad esempio:

SELECT 001 AS [Col 1], 
     901 AS [Col 2], 
     00454345345345435349 AS [Col 3], 
     03453453453454353458 AS [Col 4] 
FROM [Some Schema].[Some Table] 

E mia classe sarebbe simile a questa

public class ClassA 
    {   
     public string Col1 { get; set; }  

     public string Col2 { get; set; } 

     ///... etc 
    } 

mia applicazione si presenta così al momento

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; 
    } 

Nota: SQL non può essere modificato in alcun modo.

Attualmente sto passando attraverso il codice dapper, e la mia unica soluzione prevedibile è aggiungere del codice per "convincere" il confronto tra le colonne, ma non avere molta fortuna finora.

Ho visto su StackOverflow che ci sono cose come le estensioni dapper, ma spero di poterlo fare senza aggiungere un'estensione, altrimenti. Prenderò tutto ciò che è più veloce da implementare.

+0

Ho questo stesso bisogno. Mi sono aggirato aggiungendo alias a tutte le colonne della mia query ma è incredibilmente noioso. Le soluzioni di seguito potrebbero funzionare ma sarebbe davvero bello se Dapper potesse semplicemente aggiungere una proprietà/parametro per ignorare gli spazi invece di dover aggiungere tutti i mapper dei clienti.Questi sono nomi legali e dovrebbe essere in grado di mapparli con poco sforzo. –

risposta

8

Un'opzione sarebbe quella di passare tramite l'API dinamica/non generica e quindi recuperare i valori tramite l'API IDictionary<string,object> per riga, ma potrebbe essere un po 'noioso.

In alternativa, è possibile creare un programma di mappatura personalizzato e comunicarlo a questo proposito; per esempio:

SqlMapper.SetTypeMap(typeof(ClassA), new RemoveSpacesMap()); 

con:

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; } 
     } 
    } 
} 
+1

Grazie! Per il momento dovevo rimuovere dapper, dato che era necessario per una piccola (affrettata) prova di concetto. Ma mi piace il framework/libreria, penso che lo aggiungerò di nuovo. –

+0

@transistor puoi mostrare un esempio di questo errore? –

+0

Ah .. considerando questo suppongo che avrei dovuto implementare il metodo FindConstructor in 'RemoveSpacesMap', giusto? Oops! Scusate. – transistor1

4

Ho avuto un problema simile quando si cerca di ottenere risultati da una chiamata alla procedura di sistema sp_spaceused mappato. Il codice di Marc non ha funzionato per me in quanto lamentava di non essere in grado di trovare un costruttore predefinito. Inoltre ho reso la mia versione generica in modo che potesse essere teoricamente riutilizzata. Questo potrebbe non essere il codice di esecuzione più veloce, ma funziona per me e nella nostra situazione queste chiamate sono fatte di rado.

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; } 
     } 
    } 
} 
4

C'è un pacchetto di NuGet Dapper.FluentMap che permette di aggiungere mappature dei nomi colonna (spazi inclusi). È simile a 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())); 

vedere https://github.com/henkmollema/Dapper-FluentMap per ulteriori informazioni.

+0

Bel esempio. Molto facile da usare ed è un pacchetto NuGet – joetinger

+0

@David, ho inizializzato FluentMapper. Ma non sembra funzionare. Credo che mi manchi qualcosa. Potresti elaborare come posso farlo funzionare, se il mio codice attuale è 'return connection.Query (" SELECT 'My Name' [Nome cliente] ") Primo();', Come questo può essere fatto per lavorare a restituire oggetto cliente? – user007

+0

@ user007 puoi mostrarmi la tua classe Cliente? E dove stai facendo la mappatura? –

Problemi correlati