Convertir resultado de consulta de Linq a diccionario

346

Quiero agregar algunas filas a una base de datos usando Linq to SQL, pero quiero hacer una "verificación personalizada" antes de agregar las filas para saber si debo agregar, reemplazar o ignorar las filas entrantes. Me gustaría mantener el tráfico entre el cliente y el servidor de base de datos lo más bajo posible y minimizar el número de consultas.

Para hacer esto, quiero obtener la menor cantidad de información necesaria para la validación, y solo una vez al comienzo del proceso.

Estaba pensando en hacer algo como esto, pero obviamente, no funciona. ¿Alguien tiene una idea?

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

Lo que me gustaría tener al final sería un Diccionario, sin tener que descargar todos los objetos ObjectType de TableObject.

También consideré el siguiente código, pero estaba tratando de encontrar una manera adecuada:

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
fuente

Respuestas:

632

Intenta usar el ToDictionarymétodo de esta manera:

var dict = TableObj.ToDictionary( t => t.Key, t => t.TimeStamp );
tvanfosson
fuente
2
@pawan, es un marcador de posición para cada elemento en la enumeración y toma el tipo de los objetos en la enumeración.
tvanfosson
1
@pawan: eso no se ve bien. Esperaría que var servers = list.Select( s => new { s.ProjectName, Url = "tcp://" + s.BuildMachineName + ":" + s.PortNumber + "/CruiseManager.rem" } ).ToDictionary( s => s.ProjectName, s.Url ); esto creara un diccionario tecleado por el nombre del proyecto del nombre del proyecto / pares de url.
tvanfosson
3
¿Por qué es .Select( t => new { t.Key, t.TimeStamp } )necesaria la expresión?
Ben Collins
99
@BenCollins: creo que el intermedio .Selecthace que el SQL generado solo seleccione Key y TimeStamp, en lugar de seleccionar cada columna.
Joey Adams
1
Puede omitir este intermediario Selectsi está haciendo Linq to Object (en lugar de Linq to SQL)
Pac0
119

Mirando tu ejemplo, creo que esto es lo que quieres:

var dict = TableObj.ToDictionary(t => t.Key, t=> t.TimeStamp);
BFree
fuente
Wow ... Podría ser tan simple como eso ... Como soy bastante nuevo en programación, lo intentaré y haré un pequeño perfil para asegurarme de que, debajo del capó, no recibo el golpe de todo el objeto. Te mantendré informado.
Tipx
1
Acabo de hacer mi cheque. Lamentablemente, mientras obtengo el TableObj, recupera todos los objetos del db, así que termino recibiendo el golpe de tráfico. También verifiqué las consultas que publiqué en la segunda forma (y quería evitarlas) y solo obtuvieron los elementos necesarios. Claro que hace 2 consultas, por lo que el servidor en sí tiene que buscar dos veces las tablas, pero la asignación de objetos es bastante simple.
Tipx
77
Es posible que pueda hacer: TableObj.Select (t => new {t.Key, t.TimeStamp}). ToDictionary (t => t.Key, t => t.TimeStamp); LinqToSql debería poder notar que solo desea dos cosas (de la selección) y devolverlas. No estoy seguro de que sea lo suficientemente inteligente como para profundizar en los detalles de ToDictionary ().
Talljoe 05 de
1
¡BONITO! Aquí está la consulta resultante: SELECT [t0]. [Key], [t0]. [TimeStamp] FROM [TableObj] AS [t0]. No quiero tomar el crédito por esto, ¡así que adelante y publíquelo como respuesta! :-P
Tipx
8

Intenta lo siguiente

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

O la versión inferenciada de tipo completo

var existingItems = TableObj.ToDictionary(x => x.Key);
JaredPar
fuente
Gracias por la respuesta JaredPar. Enseñé sobre algo así, pero creo que esto devolvería los objetos completos del tipo ObjType, y quiero evitar tener que descargar los objetos completos.
Tipx
@ Tipx, ¿puede proporcionar alguna información sobre lo que desea filtrar? Adición de una cláusula de filtro es posible, pero no se puede decir de su pregunta lo que es importante
JaredPar
Todo lo que necesito saber si la "nueva fila" necesita ser agregada, ignorada o reemplazar otra fila es la marca de tiempo del objeto. Los objetos en la base de datos tienen muchos campos que no necesito para la validación y no quiero obtener el rendimiento de obtener los objetos completos. Para simplificar, obtuve una tabla en mi BD con 20 columnas, 100 000 filas y me gustaría extraer un diccionario utilizando los valores de las 2 primeras columnas.
Tipx
Acabo de comprobar las consultas del servidor generadas por ese código y, como probablemente sabías, obtiene todos los objetos.
Tipx
0

Usar espacio de nombres

using System.Collections.Specialized;

Hacer instancia de DataContextclase

LinqToSqlDataContext dc = new LinqToSqlDataContext();

Utilizar

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

Para recuperar los valores, use el espacio de nombres

   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
fuente
¿Para teclas Multilple ?
Kiquenet