Convertir le résultat de la requête Linq en dictionnaire

346

Je souhaite ajouter des lignes à une base de données à l'aide de Linq to SQL, mais je souhaite effectuer une "vérification personnalisée" avant d'ajouter les lignes pour savoir si je dois ajouter, remplacer ou ignorer les lignes entrantes. Je voudrais maintenir le trafic entre le client et le serveur DB aussi bas que possible et minimiser le nombre de requêtes.

Pour ce faire, je souhaite récupérer le moins d'informations nécessaires à la validation, et une seule fois au début du processus.

Je pensais faire quelque chose comme ça, mais évidemment, ça ne marche pas. Quelqu'un a une idée?

Dictionary<int, DateTime> existingItems = 
    (from ObjType ot in TableObj
        select (new KeyValuePair<int, DateTime>(ot.Key, ot.TimeStamp))
    )

Ce que j'aimerais avoir à la fin serait un dictionnaire, sans avoir à télécharger l'intégralité des objets ObjectType à partir de TableObject.

J'ai également considéré le code suivant, mais j'essayais de trouver un moyen approprié:

List<int> keys = (from ObjType ot in TableObj orderby ot.Key select ot.Key).ToList<int>();
List<DateTime> values = (from ObjType ot in TableObj orderby ot.Key select ot.Value).ToList<int>();
Dictionary<int, DateTime> existingItems = new Dictionary<int, DateTime>(keys.Count);
for (int i = 0; i < keys.Count; i++)
{
    existingItems.Add(keys[i], values[i]);
}
Tipx
la source

Réponses:

633

Essayez d'utiliser la ToDictionaryméthode comme ceci:

var dict = TableObj.ToDictionary( t => t.Key, t => t.TimeStamp );
tvanfosson
la source
2
@pawan, c'est un espace réservé pour chaque élément de l'énumération et prend le type des objets dans l'énumération.
tvanfosson
1
@pawan - cela ne semble pas correct. Je m'attendrais à var servers = list.Select( s => new { s.ProjectName, Url = "tcp://" + s.BuildMachineName + ":" + s.PortNumber + "/CruiseManager.rem" } ).ToDictionary( s => s.ProjectName, s.Url ); ce que cela crée un dictionnaire saisi par le nom du projet des paires nom de projet / URL.
tvanfosson
3
Pourquoi l' .Select( t => new { t.Key, t.TimeStamp } )expression est-elle nécessaire?
Ben Collins
9
@BenCollins: Je pense que l'intermédiaire .Selectfait que le SQL généré ne sélectionne que Key et TimeStamp, plutôt que de sélectionner chaque colonne.
Joey Adams
1
Vous pouvez omettre cet intermédiaire Selectsi vous faites Linq to Object (au lieu de Linq to SQL)
Pac0
119

En regardant votre exemple, je pense que c'est ce que vous voulez:

var dict = TableObj.ToDictionary(t => t.Key, t=> t.TimeStamp);
BFree
la source
Wow ... C'est peut-être aussi simple que ça ... Comme je suis assez nouveau dans la programmation, je vais essayer cela et faire un petit profilage pour m'assurer que sous le capot, je ne reçois pas le coup de tout l'objet. Je te tiendrai au courant.
Tipx
1
Je viens de faire mon chèque. Malheureusement, tout en obtenant le TableObj, il récupère tous les objets de la base de données, donc je finis par obtenir le trafic. J'ai également vérifié les requêtes que la deuxième façon j'ai publiées (et je voulais éviter) et elles n'obtiennent que les éléments nécessaires. Bien sûr, il effectue 2 requêtes, de sorte que le serveur lui-même doit rechercher deux fois les tables, mais le mappage d'objet est assez simple.
Tipx
7
Vous pourriez être en mesure de faire: TableObj.Select (t => new {t.Key, t.TimeStamp}). ToDictionary (t => t.Key, t => t.TimeStamp); LinqToSql devrait être capable de remarquer que vous ne voulez que deux choses (de la sélection) et les renvoyer. Je ne suis pas sûr qu'il soit assez intelligent pour creuser dans les spécificités de ToDictionary ().
Talljoe
1
AGRÉABLE! Voici la requête résultante: SELECT [t0]. [Key], [t0]. [TimeStamp] FROM [TableObj] AS [t0]. Je ne veux pas m'en attribuer le mérite, alors allez-y et postez-le comme réponse! :-P
Tipx
8

Essayez ce qui suit

Dictionary<int, DateTime> existingItems = 
    (from ObjType ot in TableObj).ToDictionary(x => x.Key);

Ou la version inférenciée à part entière

var existingItems = TableObj.ToDictionary(x => x.Key);
JaredPar
la source
Merci pour la réponse JaredPar. J'ai enseigné quelque chose comme ça, mais je pense que cela retournerait les objets entiers de type ObjType, et je voulais éviter d'avoir à télécharger les objets entiers.
Tipx
@Tipx, pouvez-vous fournir des informations sur ce que vous souhaitez filtrer? L'ajout d'une clause de filtrage est possible, mais je ne peux pas dire à partir de votre question ce qui est important
JaredPar
Tout ce dont j'ai besoin pour savoir si la "nouvelle ligne" doit être ajoutée, ignorée ou remplacer une autre ligne est l'horodatage de l'objet. Les objets dans la base de données ont beaucoup de champs dont je n'ai pas besoin pour la validation et je ne veux pas obtenir les performances de l'obtention des objets entiers. Pour rester simple, j'ai un tableau dans mon BD avec 20 colonnes, 100 000 lignes et je voudrais extraire un dictionnaire en utilisant les valeurs des 2 premières colonnes.
Tipx
Je viens de vérifier les requêtes du serveur générées par ce code et comme vous le savez probablement, il obtient les objets entiers.
Tipx
0

Utiliser l'espace de noms

using System.Collections.Specialized;

Créer une instance de DataContextclasse

LinqToSqlDataContext dc = new LinqToSqlDataContext();

Utilisation

OrderedDictionary dict = dc.TableName.ToDictionary(d => d.key, d => d.value);

Afin de récupérer les valeurs, utilisez l'espace de noms

   using System.Collections;

ICollection keyCollections = dict.Keys;
ICOllection valueCollections = dict.Values;

String[] myKeys = new String[dict.Count];
String[] myValues = new String[dict.Count];

keyCollections.CopyTo(myKeys,0);
valueCollections.CopyTo(myValues,0);

for(int i=0; i<dict.Count; i++)
{
Console.WriteLine("Key: " + myKeys[i] + "Value: " + myValues[i]);
}
Console.ReadKey();
Salman Mushtaq
la source
Pour les clés Multilple ?
Kiquenet