2015-09-24 6 views
6

Ich weiß, dass ich ein ParameterDirection mit Dapper.DynamicParameters verwenden:Kann ein Dapper DynamicParameters-Objekt wie ein Parameterwörterbuch aufgezählt werden?

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

Aber kann ich so tun, wenn eine Dictionary<string, object> mit?

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

Alternativ, wie kann ich iterieren einem DynamicParameters, um die Parameternamen und Werte zu erhalten?

Originaltitel:

Kann ein Dapper Parameter mit Parameterdirection hinzugefügt werden, um einen Wörterbuch verwenden?

+0

Warum Sie eine 'Dictionary' verwenden? – torvin

+0

Ich kann über ein Wörterbuch iterieren. Ich kann nicht über alles, was DynamicParameters ist, iterieren. –

+0

Dann müssten Sie Ihre eigene Datenstruktur erstellen, um 'ParameterDirection' und' DbType' zusammen mit dem Parameterwert zu speichern und im Dic abzuspeichern. Dann schreibe Code, um ihn in 'DynamicParameters' zu konvertieren. – torvin

Antwort

6

Es scheint ein Fehler in Dapper zu sein. Dies wird bestätigt, um im neuesten NuGet-Paket zu arbeiten:

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

Allerdings ist es ein bisschen ausführlich. unter Verwendung der lokal Dapper Quelle (kein NuGet Paket), konnte ich ohne Fehler diesen Code auszuführen (Wie des Schreibens, das commit b77e53):

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

Nach Charles Burns' comment, es immer noch eine Ausnahme auslöst, die mich führt zu glauben, dass der Patch es noch nicht in NuGet geschafft hat. Das Festschreiben, das Get<dynamic> repariert, ist here

+1

Kurz bevor ich deinen letzten Kommentar gelesen habe, Ich habe mich hingesetzt, um parallele Dictionary/DynamicParameters zu implementieren, um Ersteres zum Abruf, letzteres zur Ausführung zu verwenden. Ich hätte danach mindestens sechs Mal duschen müssen. –

2

Das Objekt DynamicParameters kann mehrere Abschnitte für jedes Mal enthalten, das es angefügt wurde. Es ist also nicht nötig, durch ParameterNames (es wird leer sein) wie in der obigen Antwort zu iterieren.

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

und GetPropertyValuePairs(..) ist

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

Interessant. Mir war nicht klar, dass Parameter aufgrund von Kompartimentierung verborgen werden können. Das ist mir noch nicht passiert - Robs erste 'foreach' funktioniert für mich seit dem Dapper-Patch, aber das könnte daran liegen, dass ich ein einziges' DynamicParameters'-Objekt pro Transaktion erstelle und es nur einmal benutze. –

+0

Ja Charles, 'foreach' funktioniert gut, wenn Sie die' DyanmicParameters' mit einzelnen Parametern anhängen: 'dynParams.Add (" PARAM_1 ", aValue); ... 'funktioniert aber nicht, wenn Sie es an Objekte anhängen, die folgende Parameter enthalten:' dynParams.AddDynamicParams (neu {PARAM_1 = aValue1, PARAM_2 = aValue2}); 'vielleicht sollte ich sogar 'if (dynamicParams.ParameterNames.Any()) '' von 'ToParametersDictionary (..)' Methode und überprüfen Sie die Temporationen in allen Fällen. – Oleg

Verwandte Themen