Pracuję z C # i .NET Framework 4.5.1, pobierając dane z bazy danych SQL Server z Entity Framework 6.1.3.
Mam to:
codes = codesRepo.SearchFor(predicate)
.Select(c => new Tuple<string, byte>(c.Id, c.Flag))
.ToList();
Kiedy go uruchamiam, otrzymuję następujący komunikat:
LINQ to Entities obsługuje tylko konstruktory i inicjatory bez parametrów.
Nie wiem, jak mam stworzyć krotkę, ponieważ wszystkie przykłady, które znalazłem, są w większości takie jak ten.
Próbowałem tego:
codes = codesRepo.SearchFor(predicate)
.Select(c => Tuple.Create(c.Id, c.Flag))
.ToList();
I otrzymaj ten błąd:
LINQ to Entities nie rozpoznaje metody „System.Tuple” 2 [System.String, System.Byte] Create [String, Byte] (System.String, Byte) ”i tej metody nie można przetłumaczyć na wyrażenie magazynu.
Gdzie jest problem?
c#
entity-framework
linq
tuples
VansFannel
źródło
źródło
Odpowiedzi:
Podczas gdy odpowiedź przez octavioccl prac, to lepiej do pierwszego projektu wynik zapytania do anonimowego typu, a następnie przełączyć się na przeliczalne i przekształcić ją w krotce. W ten sposób twoje zapytanie pobierze z bazy danych tylko potrzebne pola.
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
Uwaga: powyższa zasada dotyczy EF6. EF Core w naturalny sposób obsługuje krotki (w projekcji lub jako klucze łączenia / grup) za pośrednictwem konstruktora krotek, np. Oryginalne zapytanie po prostu działa
codes = codesRepo.SearchFor(predicate) .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
ale nie
Tuple.Create
metoda (EF Core 2.x).źródło
.Select(c => new { c.Id, c.Flag, c.Foo?.Code })
nie działa.?.
nie jest obsługiwany w drzewach wyrażeń. Ale poza tym możesz rozszerzyć typ anonimowy o dowolną liczbę wartości - po prostu nie zapomnij ich nazwać w razie potrzeby :) np.c => new { c.Id, c.Flag, Code = (int?)c.Foo.Code }
Tylko zaktualizowana odpowiedź dla języka C # 7, teraz możesz użyć prostszej składni do tworzenia ValueTuples.
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => (c.Id, c.Flag)) .ToList();
Możesz teraz nawet nazwać właściwości krotki:
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) // anonymous type .AsEnumerable() .Select(c => (Id: c.Id, Flag: c.Flag)) // ValueTuple .ToList();
Więc zamiast używać go jako Item1 lub Item2, możesz uzyskać do niego dostęp jako Id lub Flag.
Więcej dokumentów na temat wyboru między anonimowymi a krotkami
źródło
Spróbuj tego:
Zostałem poinformowany, że to nie jest akceptowane w LINQ to entity.
Inną opcją byłoby pobranie wyniku do pamięci przed wybraniem. Jeśli masz zamiar to zrobić, zalecałbym wykonanie całego filtrowania przed .AsEnumerable (), ponieważ oznacza to, że wycofujesz tylko wyniki, które chcesz, w przeciwieństwie do wycofywania całej tabeli, a następnie filtrowania.
również Tuple.Create (c.Id, c.Flag) można zmienić na nowy Tuple (c.Id, c.Flag), jeśli chcesz, aby kod był nieco bardziej wyraźny w typach krotek
źródło
W linq do encji możesz rzutować na anonimowy typ lub na DTO. Aby uniknąć tego problemu, możesz użyć
AsEnumerable
metody rozszerzenia:codes = codesRepo.SearchFor(predicate).AsEnumerable(). .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
Ta metoda umożliwia pracę z Linq to Object zamiast Linq to Entities , więc po wywołaniu jej możesz rzutować wynik zapytania w dowolne miejsce. Zaletą użycia
AsEnumerable
zamiast tegoToList
jest to, żeAsEnumerable
nie wykonuje zapytania, zachowuje odroczone wykonanie. Dobrym pomysłem jest zawsze filtrowanie danych przed wywołaniem jednej z tych metod.źródło
Znalazłem odpowiedź:
źródło
Użyj tej metody, aby to zrobić, i użyj asynchronicznego.
var codes = await codesRepo.SearchFor(predicate) .Select(s => new { Id = s.Id, Flag = s.Flag }).FirstOrDefaultAsync(); var return_Value = new Tuple<string, byte>(codes.Id, codes.Flag);
źródło
Tylko moje dwa centy: kilka razy mnie to złapało z nazwami typów:
Kilka przykładów Noddy:
private Tuple<string, byte> v1() { return new Tuple<string, byte>("", 1); } private (string, int) v2() { return ("", 1); } private (string Id, byte Flag) v3() { return ("", 1); }
Pozdrowienia.
źródło
public (string Id, byte Flag) SearchFor(Expression predicate)
, ale to nie ma znaczenia. Dwa centy nie powinny być odpowiedzią, ale komentarzem.