web-dev-qa-db-fra.com

Comment mapper à un objet Dictionary à partir des résultats de la base de données à l'aide de Dapper Dot Net?

Si j'ai une requête simple telle que:

string sql = "SELECT UniqueString, ID  FROM Table";

et je veux le mapper à un objet dictionnaire tel que:

Dictionary<string, int> myDictionary = new Dictionary<string, int>();      

Comment pourrais-je faire cela avec Dapper?

Je suppose que c'est quelque chose comme:

myDictionary = conn.Query<string, int>(sql, new {  }).ToDictionary();

Mais je ne peux pas comprendre la syntaxe appropriée.

55
jpshook

Il y a plusieurs façons déjà montrées; personnellement, j'utiliserais juste l'api non générique:

var dict = conn.Query(sql, args).ToDictionary(
    row => (string)row.UniqueString,
    row => (int)row.Id);
101
Marc Gravell

Fonctionne également sans classe supplémentaire:

var myDictionary = conn.Query<string, int, KeyValuePair<string,int>>(sql, (s,i) => new KeyValuePair<string, int>(s,i))
    .ToDictionary(kv => kv.Key, kv => kv.Value);

[~ # ~] note [~ # ~] : lors de l'utilisation de la version Dapper.NET 3.5, la méthode Query qui prend les premier, second et retour types nécessite de spécifier plus de paramètres, car les versions .NET 4.0 et .NET 4.5 tirent parti de arguments facultatifs .

Dans ce cas, le code suivant devrait fonctionner:

string splitOn = "TheNameOfTheValueColumn";
var myDictionary = conn.Query<string, int, KeyValuePair<string,int>>(sql, (s,i) => new KeyValuePair<string, int>(s,i), null, null, false, splitOn, null, null)
        .ToDictionary(kv => kv.Key, kv => kv.Value);

La plupart des arguments reviendront à une valeur par défaut, mais splitOn est requis, car sinon, la valeur par défaut sera 'id'.

Pour une requête qui renvoie deux colonnes, ' [~ # ~] id [~ # ~]' et ' Description', splitOn doit être réglé sur ' Description'.

19
Tim Schmelter
string strSql = "SELECT DISTINCT TableID AS [Key],TableName AS [Value] FROM dbo.TS_TStuctMaster";
Dictionary<string,string> dicts = sqlConnection.Query<KeyValuePair<string,string>>(strSql).ToDictionary(pair => pair.Key, pair => pair.Value);

Vous pouvez utiliser des alias et des types forts.

Les alias sont les points clés, qui correspondent aux attributs de type et valeur de type KeyValuePair.

Il fonctionne sous une frappe forte et fonctionne bien.

Je n'aime pas le type dynamique. Cela amène un désastre dans certaines situations. De plus, le boxing et le unboxing entraînent une perte de performances.

12
Allen.Cai

Je ne sais pas si ce que vous essayez de faire est possible. Si vous définissez une classe pour mapper la requête à cela devient beaucoup plus trivial:

public class MyRow
{
    public int Id { get; set; }
    public string UniqueString { get; set; }
}

Ensuite, vous feriez juste ceci:

var sql = "SELECT UniqueString, ID  FROM Table";
var myDictionary = conn.Query<MyRow>(sql).ToDictionary(row => row.UniqueString, row => row.Id);
7
w.brian

Dapper a également une méthode d'extension pour ExecuteReader. Donc, vous pouvez également faire ceci:

var sql = "SELECT UniqueString, ID  FROM Table";
var rows = new List<Dictionary<string, int>>();
using (var reader = cn.ExecuteReader(sql)) {
    while (reader.Read()) {
        var dict = new Dictionary<string, int>();
        for (var i = 0; i < reader.FieldCount; i++) {
            dict[reader.GetName(i)] = reader.GetInt32(i);
        }
        rows.Add(dict);
    }
}

Cette approche fonctionne sans connaître les noms des colonnes. De plus, si vous ne connaissez pas les types de données, vous pouvez remplacer Dictionary<string,int> Par Dictionary<string,object> Et GetInt32(i) par GetValue(i).

6
dalenewman

Si vous utilisez> .net 4.7 ou netstandard2, vous pouvez utiliser des tuples de valeur. le code est gentil et concis et il n'y a pas d'utilisation de dynamique.

var sql = "SELECT UniqueString, Id  FROM Table";
var dict = conn.Query<(string UniqueString, int Id)>(sql)
           .ToDictionary(t => t.UniqueString,t => t.Id);
3
herostwist