Korzystając z prostego przykładu poniżej, jaki jest najlepszy sposób na zwrócenie wyników z wielu tabel za pomocą Linq do SQL?
Powiedzmy, że mam dwie tabele:
Dogs: Name, Age, BreedId
Breeds: BreedId, BreedName
Chcę zwrócić wszystkie psy z nimi BreedName
. Powinienem sprawić, by wszystkie psy używały czegoś takiego bez problemu:
public IQueryable<Dog> GetDogs()
{
var db = new DogDataContext(ConnectString);
var result = from d in db.Dogs
join b in db.Breeds on d.BreedId equals b.BreedId
select d;
return result;
}
Ale jeśli chcę psów z rasami i spróbuję tego, mam problemy:
public IQueryable<Dog> GetDogsWithBreedNames()
{
var db = new DogDataContext(ConnectString);
var result = from d in db.Dogs
join b in db.Breeds on d.BreedId equals b.BreedId
select new
{
Name = d.Name,
BreedName = b.BreedName
};
return result;
}
Teraz zdaję sobie sprawę, że kompilator nie pozwoli mi zwrócić zestawu anonimowych typów, ponieważ oczekuje Psy, ale czy istnieje sposób, aby to zwrócić bez konieczności tworzenia niestandardowego typu? Czy też muszę utworzyć własną klasę DogsWithBreedNames
i określić ten typ w zaznaczeniu? Czy jest inny łatwiejszy sposób?
c#
linq
linq-to-sql
Jonathan S.
źródło
źródło
foreach (var cust in query) Console.WriteLine("id = {0}, City = {1}", cust.CustomerID, cust.City);
Odpowiedzi:
Zwykle wybieram ten wzór:
Oznacza to, że masz dodatkową klasę, ale kodowanie jest szybkie i łatwe, łatwo rozszerzalne, wielokrotnego użytku i bezpieczne dla typu.
źródło
Państwo może powrócić anonimowych typów, ale to naprawdę nie jest ładny .
W tym przypadku myślę, że znacznie lepiej byłoby stworzyć odpowiedni typ. Jeśli ma być używany tylko z typu zawierającego metodę, uczyń go typem zagnieżdżonym.
Osobiście chciałbym, aby C # dostał „nazwane typy anonimowe” - tj. Takie samo zachowanie jak typy anonimowe, ale z nazwami i deklaracjami własności, ale to wszystko.
EDYCJA: Inni sugerują powrót psów, a następnie uzyskanie dostępu do nazwy rasy za pośrednictwem ścieżki własności itp. To całkowicie rozsądne podejście, ale IME prowadzi do sytuacji, w których wykonałeś zapytanie w określony sposób ze względu na dane, które chcesz użyj - a meta-informacje zostaną utracone, gdy tylko wrócisz
IEnumerable<Dog>
- zapytanie może się spodziewać że użyjesz (powiedzmy),Breed
a nie zOwner
powodu niektórych opcji ładowania itp., ale jeśli zapomnisz o tym i zaczniesz używać innych właściwości, aplikacja może działać, ale nie tak skutecznie, jak pierwotnie przewidywano. Oczywiście, mógłbym mówić o śmieciach lub o nadmiernej optymalizacji itp.źródło
Żeby dodać wartość dwóch centów :-) Niedawno nauczyłem się obsługiwać anonimowe obiekty. Można go używać tylko podczas atakowania frameworku .NET 4 i to tylko podczas dodawania odwołania do System.Web.dll, ale jest to dość proste:
Aby móc dodać odwołanie do System.Web.dll, musisz postępować zgodnie ze wskazówkami rushonerok : Upewnij się, że docelową strukturą [projektu] jest „.NET Framework 4”, a nie „.NET Framework 4 Client Profile”.
źródło
Nie, nie możesz zwrócić anonimowych typów bez przechodzenia przez pewne sztuczki.
Jeśli nie używasz C #, to czego byś szukał (zwracając wiele danych bez konkretnego typu) nazywa się Tuple.
Istnieje wiele implementacji krotek C #, używając tej pokazanej tutaj , twój kod działałby w ten sposób.
A na stronie dzwoniącej:
źródło
... select Tuple.Create(d, b)
.Możesz zrobić coś takiego:
źródło
ToList()
Najpierw musisz użyć metody, aby pobrać wiersze z bazy danych, a następnie wybrać elementy jako klasę. Spróbuj tego:Tak więc sztuczka jest pierwsza
ToList()
. Natychmiast wykonuje zapytanie i pobiera dane z bazy danych. Druga sztuczka to wybieranie przedmiotów i używanie inicjatora obiektów do generowania nowych obiektów z załadowanymi elementami.Mam nadzieję że to pomoże.
źródło
W C # 7 możesz teraz używać krotek! ... co eliminuje potrzebę tworzenia klasy tylko po to, aby zwrócić wynik.
Oto przykładowy kod:
Może być jednak konieczne zainstalowanie pakietu nuget System.ValueTuple.
źródło
Teraz zdaję sobie sprawę, że kompilator nie pozwoli mi zwrócić zestawu anonimowych typów, ponieważ oczekuje Psy, ale czy istnieje sposób, aby to zwrócić bez konieczności tworzenia niestandardowego typu?
Użyj obiektu use, aby zwrócić listę typów Anonimowych bez tworzenia typu niestandardowego. Będzie to działać bez błędu kompilatora (w .net 4.0). Zwróciłem listę klientowi, a następnie przeanalizowałem ją w JavaScript:
źródło
Po prostu wybierz psy, a następnie użyj
dog.Breed.BreedName
, to powinno działać dobrze.Jeśli masz dużo psów, użyj DataLoadOptions.LoadWith, aby zmniejszyć liczbę wywołań db.
źródło
Nie możesz zwrócić anonimowych typów bezpośrednio, ale możesz zapętlić je za pomocą ogólnej metody. Podobnie jak większość metod rozszerzenia LINQ. Nie ma tam magii, choć wygląda na to, że zwrócą anonimowe typy. Jeśli parametr jest anonimowy, wynik może być również anonimowy.
Poniżej przykład oparty na kodzie z pierwotnego pytania:
źródło
Cóż, jeśli oddajesz Psy, zrobiłbyś:
Jeśli chcesz rasy ładowanej chętnie, a nie leniwie, po prostu użyj odpowiedniej konstrukcji DataLoadOptions .
źródło
BreedId
wDog
tabeli jest oczywiście klucz obcy do odpowiedniego wiersza wBreed
tabeli. Jeśli baza danych jest poprawnie skonfigurowana, LINQ to SQL powinien automatycznie utworzyć powiązanie między dwiema tabelami. Wynikowa klasa psów będzie miała właściwość rasy, a klasa rasy powinna mieć kolekcję psów. Konfigurując go w ten sposób, możesz nadal powrócićIEnumerable<Dog>
, który jest przedmiotem zawierającym własność rasy. Jedynym zastrzeżeniem jest to, że musisz wstępnie załadować obiekt rasy wraz z obiektami psa w zapytaniu, aby można było uzyskać do nich dostęp po usunięciu kontekstu danych i (jak sugerował inny plakat) wykonać metodę w kolekcji, która spowoduje zapytanie, które należy wykonać natychmiast (w tym przypadku ToArray):Dostęp do rasy dla każdego psa jest więc trywialny:
źródło
Jeśli głównym pomysłem jest, aby instrukcja SQL select wysyłana do serwera bazy danych zawierała tylko wymagane pola, a nie wszystkie pola encji, możesz to zrobić:
źródło
Spróbuj tego, aby uzyskać dynamiczne dane. Możesz przekonwertować kod dla List <>
źródło
Jeśli masz konfigurację relacji w bazie danych z ograniczeniem klucza foriegn na Breed, czy już tego nie rozumiesz?
Mogę teraz zadzwonić:
A w kodzie, który to nazywa:
Więc w twoim przypadku będziesz nazywał coś w rodzaju dog.Breed.BreedName - jak powiedziałem, zależy to od skonfigurowania bazy danych z tymi relacjami.
Jak wspomnieli inni, DataLoadOptions pomoże zmniejszyć liczbę wywołań bazy danych, jeśli jest to problem.
źródło
To nie do końca odpowiada na twoje pytanie, ale Google zaprowadziło mnie tutaj na podstawie słów kluczowych. W ten sposób możesz wyszukać anonimowy typ z listy:
źródło