Konwertuj wynik zapytania Linq na słownik

346

Chcę dodać niektóre wiersze do bazy danych przy użyciu Linq do SQL, ale chcę wykonać „niestandardowe sprawdzenie” przed dodaniem wierszy, aby wiedzieć, czy muszę dodać, zamienić lub zignorować przychodzące wiersze. Chciałbym utrzymać ruch między klientem a serwerem DB na jak najniższym poziomie i zminimalizować liczbę zapytań.

Aby to zrobić, chcę pobrać tak mało informacji, jak jest to wymagane do weryfikacji i tylko raz na początku procesu.

Myślałem o zrobieniu czegoś takiego, ale oczywiście to nie działa. Czy ktoś ma pomysł?

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

Na koniec chciałbym mieć Słownik, bez konieczności pobierania całych obiektów ObjectType z TableObject.

Rozważyłem również następujący kod, ale próbowałem znaleźć właściwy sposób:

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
źródło

Odpowiedzi:

633

Spróbuj użyć metody w ten ToDictionarysposób :

var dict = TableObj.ToDictionary( t => t.Key, t => t.TimeStamp );
tvanfosson
źródło
2
@pawan, jest symbolem zastępczym dla każdego elementu w wyliczeniu i przyjmuje typ obiektów w wyliczeniu.
tvanfosson
1
@pawan - to nie wygląda dobrze. Spodziewałbym się, że var servers = list.Select( s => new { s.ProjectName, Url = "tcp://" + s.BuildMachineName + ":" + s.PortNumber + "/CruiseManager.rem" } ).ToDictionary( s => s.ProjectName, s.Url ); utworzy to słownik oparty na nazwie projektu pary nazwa / adres projektu.
tvanfosson
3
Dlaczego .Select( t => new { t.Key, t.TimeStamp } )wyrażenie jest konieczne?
Ben Collins,
9
@BenCollins: Myślę, że pośredni .Selectpowoduje, że wygenerowany SQL wybiera tylko Key i TimeStamp, a nie wybiera każdą kolumnę.
Joey Adams
1
Możesz pominąć tego pośrednika, Selectjeśli robisz Linq do Object (zamiast Linq do SQL)
Pac0
119

Patrząc na twój przykład, myślę, że tego właśnie chcesz:

var dict = TableObj.ToDictionary(t => t.Key, t=> t.TimeStamp);
BFree
źródło
Wow ... To może być takie proste ... Ponieważ jestem całkiem nowy w programowaniu, spróbuję to zrobić i wykonam małe profilowanie, aby upewnić się, że pod maską nie dostanę uderzenia całego obiektu. Będę was informować.
Tipx
1
Właśnie zrobiłem czek. Niestety, podczas pobierania TableObj, pobiera wszystkie obiekty z bazy danych, więc trafiam w trafic. Sprawdziłem również zapytania, które opublikowałem w drugi sposób (i chciałem ich uniknąć), i dostają tylko niezbędne elementy. Jasne, że wykonuje 2 zapytania, więc sam serwer musi przeszukiwać dwa razy tabele, ale mapowanie obiektów jest dość proste.
Tipx
7
Możesz być w stanie: TableObj.Select (t => new {t.Key, t.TimeStamp}). ToDictionary (t => t.Key, t => t.TimeStamp); LinqToSql powinien być w stanie zauważyć, że chcesz tylko dwie rzeczy (z wyboru) i zwrócić je. Nie jestem pewien, czy jest wystarczająco inteligentny, aby zagłębić się w szczegóły ToDictionary ().
Talljoe
1
MIŁY! Oto wynikowe zapytanie: SELECT [t0]. [Key], [t0]. [TimeStamp] FROM [TableObj] AS [t0]. Nie chcę przypisywać sobie za to zasługi, więc napisz to jako odpowiedź! :-P
Tipx
8

Spróbuj wykonać następujące czynności

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

Lub pełna wersja wnioskowania typu

var existingItems = TableObj.ToDictionary(x => x.Key);
JaredPar
źródło
Dzięki za odpowiedź JaredPar. Uczyłem o czymś takim, ale myślę, że zwróciłoby to wszystkie obiekty typu ObjType i chcę uniknąć konieczności pobierania całych obiektów.
Tipx
@Tipx, czy możesz podać informacje na temat tego, co chcesz filtrować? Dodanie klauzuli filtrowania jest możliwe, ale z twojego pytania nie mogę powiedzieć, co jest ważne
JaredPar
Muszę tylko wiedzieć, czy „nowy wiersz” musi zostać dodany, zignorowany lub zastąpiony innym wierszem jest znacznik czasu obiektu. Obiekty w bazie danych mają wiele pól, których nie potrzebuję do sprawdzania poprawności i nie chcę uzyskać wydajności w zakresie uzyskiwania całych obiektów. Dla uproszczenia dostałem tabelę na moim BD z 20 kolumnami, 100 000 wierszy i chciałbym wyodrębnić słownik przy użyciu wartości pierwszych 2 kolumn.
Tipx
Właśnie sprawdziłem zapytania serwera wygenerowane przez ten kod i jak zapewne wiesz, pobiera całe obiekty.
Tipx
0

Użyj przestrzeni nazw

using System.Collections.Specialized;

Wykonaj instancję DataContextklasy

LinqToSqlDataContext dc = new LinqToSqlDataContext();

Posługiwać się

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

Aby pobrać wartości, użyj przestrzeni nazw

   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
źródło
Do kluczy Multilple ?
Kiquenet,