2015-09-24 9 views
6

So che posso utilizzare un ParameterDirection con Dapper.DynamicParameters:Un oggetto Dapper DynamicParameters può essere enumerato come un dizionario di parametri?

var parameters = new DynamicParameters(); 
parameters.Add("iparam", 42); 
parameters.Add("oparam", null, DbType.Int32, ParameterDirection.Output); 
connection.Execute(sql, parameters); 

Ma posso fare in modo che quando si utilizza un Dictionary<string, object>?

var parameters = new Dictionary<string, object>(); 
parameters.Add("iparam", 42); 
parameters.Add("oparam", /* ??? */); 
connection.Execute(sql, parameters); 

In alternativa, come posso iterare su una DynamicParameters al fine di ottenere i nomi ei valori dei parametri?

Titolo originale:

Può un parametro Dapper con ParameterDirection essere aggiunti usando un dizionario ?

+0

Perché si vuole usare un 'Dictionary'? – torvin

+0

Posso scorrere su un dizionario. Non riesco a scorrere su qualsiasi DynamicParameters. –

+0

Quindi dovresti creare la tua struttura dati per contenere 'ParameterDirection' e' DbType' insieme al valore del parametro e memorizzarlo nel dic. E poi scrivi il codice per convertirlo in 'DynamicParameters' – torvin

risposta

6

Sembra un errore in Dapper. Questo è confermato per funzionare nell'ultimo pacchetto NuGet:

foreach (var paramName in parameters.ParameterNames) 
{ 
    var value = ((SqlMapper.IParameterLookup)parameters)[paramName]; 
} 

Tuttavia, è un po 'prolisso. Localmente utilizzando la Dapper sorgente (non un pacchetto NuGet), ero in grado di eseguire questo codice senza errori (come di scrittura che di commit b77e53):

foreach (var paramName in parameters.ParameterNames) 
{ 
    var value = parameters.Get<dynamic>(paramName); 
} 

Secondo Charles Burns' comment, si getta ancora un'eccezione, che mi porta credere che la patch non sia ancora arrivata a NuGet. Il commit che corregge Get<dynamic> è here

+1

Poco prima di leggere il tuo ultimo commento, Ero seduto per implementare il dizionario parallelo/DynamicParameters per usare il primo per il recupero, il secondo per l'esecuzione. Avrei dovuto fare la doccia almeno sei volte dopo. –

2

L'oggetto DynamicParameters può contenere diverse sezioni per ogni volta che è stato aggiunto. Quindi non è da enumerare attraverso ParameterNames (sarà vuoto) come nella risposta sopra.

public static Dictionary<string, object> ToParametersDictionary(this DynamicParameters dynamicParams) 
{ 
    var argsDictionary = new Dictionary<String, Object>(); 
    var iLookup = (SqlMapper.IParameterLookup) dynamicParams; 
    //if (dynamicParams.ParameterNames.Any()) 
    //{ 
     // read the parameters added via dynamicParams.Add("NAME", value) 
     foreach (var paramName in dynamicParams.ParameterNames) 
     { 
      var value = iLookup[paramName]; 
      argsDictionary.Add(paramName, value); 
     } 
    //} 
    //else 
    //{ 
     // read the "templates" field containing dynamic parameters section added 
     // via dynamicParams.Add(new {PARAM_1 = value1, PARAM_2 = value2}); 
     var templates = dynamicParams.GetType().GetField("templates", BindingFlags.NonPublic | BindingFlags.Instance); 
     if (templates != null) 
     { 
      var list = templates.GetValue(dynamicParams) as List<Object>; 
      if (list != null) 
      { 
       // add properties of each dynamic parameters section 
       foreach (var objProps in list.Select(obj => obj.GetPropertyValuePairs().ToList())) 
       { 
        objProps.ForEach(p => argsDictionary.Add(p.Key, p.Value)); 
       } 
      } 
     } 
    } 
    return argsDictionary; 
} 

e GetPropertyValuePairs(..) è

public static Dictionary<string, object> GetPropertyValuePairs(this object obj, String[] hidden = null) 
{ 
    var type = obj.GetType(); 
    var pairs = hidden == null 
     ? type.GetProperties() 
      .DistinctBy(propertyInfo => propertyInfo.Name) 
      .ToDictionary(
       propertyInfo => propertyInfo.Name, 
       propertyInfo => propertyInfo.GetValue(obj, null)) 
     : type.GetProperties() 
      .Where(it => !hidden.Contains(it.Name)) 
      .DistinctBy(propertyInfo => propertyInfo.Name) 
      .ToDictionary(
       propertyInfo => propertyInfo.Name, 
       propertyInfo => propertyInfo.GetValue(obj, null)); 
    return pairs; 
} 

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) 
{ 
    var seenKeys = new HashSet<TKey>(); 
    return source.Where(element => seenKeys.Add(keySelector(element))); 
} 
+0

Interessante. Non mi rendevo conto che i parametri potevano essere nascosti a causa della compartimentazione. Questo non mi è ancora successo - il primo 'foreach' di Rob funziona per me dal momento che la patch di Dapper, ma potrebbe essere perché costruisco un singolo oggetto' DynamicParameters' per transazione e lo uso solo una volta. –

+0

Sì Charles, 'foreach' funziona correttamente se si aggiungono' DyanmicParameters' con parametri singoli: 'dynParams.Add (" PARAM_1 ", aValue); ... 'ma non funziona se lo aggiungi ad oggetti contenenti i parametri:' dynParams.AddDynamicParams (new {PARAM_1 = aValue1, PARAM_2 = aValue2}); 'forse dovrei anche rimuovere' if (dynamicParams.ParameterNames.Any()) 'dal metodo' ToParametersDictionary (..) 'e controlla i templaces in tutti i casi. – Oleg