2009-11-17 13 views
6

Mam bardzo złożone zapytanie Linq do SQL, które zwraca zestaw wyników z bazy danych Microsoft SQL Server. Zapytanie jest tworzone przy użyciu składni podobnej do:Linq Query zwraca niepoprawny zestaw wyników

Dim db as MyDataContext = MyGetDataContextHelper() 
Dim qry = From rslt in db.MyView Select ColumnList 

If userParam1 IsNot Nothing Then 
    qry = qry.Where(lambda for the filter) 
End If 

etc.... 

Return qry.ToList() 

Istnieje kilka filtrów określone przez użytkownika do zapytania, w tym jeden, który robi się geograficzny szukanie promienia.

Oto problem. Na końcu mam wywołanie "Przerwa" na zestawie "ToList". Kiedy przerwa jest trafiona, używam Linq do SQL Debug Visualizer, aby zobaczyć wygenerowaną instrukcję SQL. Skopiuję tę złożoną instrukcję SQL do okna zapytania programu SQL Server Management Studio i wykonuję ją względem mojej bazy danych, aby uzyskać dokładnie żądany zestaw wyników. Zatem wygenerowany kod SQL wydaje się dawać pożądany wynik. Jednak po uruchomieniu metody "ToList" obiektu zapytania zwrócona lista zawiera mniej wierszy i kilka różnych wierszy. Próbowałem również tego przy użyciu zapisu właściwości dziennika DataContext do pliku, z tym samym wynikiem. Kwerenda generuje poprawny zestaw wyników w SQL Management Studio, ale niepoprawne wyniki z metody ToList.

Jak to możliwe? Jeśli wygenerowany kod SQL jest po prostu przekazywany przez połączenie z serwerem SQL, czy nie powinien generować dokładnie zestawu wyników widzianego w SQL Server Management Studio? Zakładam, że nie rozumiem czegoś z mechanizmu Linq do SQL, to znaczy, że nie jest to tylko przekazywanie do SQL Server. Czy to jest poprawne?

EDIT: Jak na żądanie poniżej, tutaj jest znacznie skrócona wersja SQL, który jest generowany przez Linq, przy czym większość z kolumn wynikowych usuniętymi dla zwięzłości. Wygeneruje poprawny wynik w SQL Management Studio, ale wynik zwracany do mojej aplikacji jest inny.

SELECT [t3].[Id] 
FROM (
    SELECT DISTINCT [t1].[Id] 
    FROM (
     SELECT [t0].[Id], [t0].[ItemDate] 
     FROM [dbo].[MySearchView] AS [t0] 
     ) AS [t1] 
    WHERE (EXISTS(
     SELECT NULL AS [EMPTY] 
     FROM [dbo].[ZipCoverage] AS [t2] 
     WHERE ([t2].[Id] = [t1].[Id]) 
     AND ([t2].[Latitude] >= (41.09046 - (0.5))) 
     AND ([t2].[Latitude] <= (41.09046 + (0.5))) 
     AND ([t2].[Longitude] >= (-73.43106 - (0.5))) 
     AND ([t2].[Longitude] <= (-73.43106 + (0.5))) 
     AND (ABS(3956.08833132861 * 2 * ATN2(SQRT(POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) - 0.717163818159029)/(CONVERT(Float,2))), 2) + (COS(0.717163818159029) * COS((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) * POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Longitude]) - -1.28161377022951)/(CONVERT(Float,2))), 2))), SQRT((1 - POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) - 0.717163818159029)/(CONVERT(Float,2))), 2)) + (COS(0.717163818159029) * COS((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) * POWER(SIN(((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Longitude])/(CONVERT(Float,2))), 2))))) <= 5))) 
     AND ([t1].[ItemDate] <= '11/17/2009 8:12:42 PM') 
    ) AS [t3] 

UPDATE 2009-11-17 mógł skontaktować MS dotyczące tej kwestii. Utworzono przykładową aplikację, którą przesłałem do ich przedstawiciela ds. Pomocy technicznej. Oni powielił problem i badajĘ ​​.... Odpisze odpowiedź, gdy otrzymam odpowiedź.

AKTUALIZACJA 2009-12-21 Wreszcie otrzymano poprawną odpowiedź z pomocą firmy Microsoft. Zapoznaj się z moją akceptowaną odpowiedzią poniżej, aby uzyskać wyjaśnienie.

+1

Czy możesz wysłać swoje aktualne zapytanie LINQ? Powiedziałeś, że to bardzo skomplikowane. Biorąc pod uwagę, że wszystko inne wydaje się być w porządku, pozostała opcja polega na tym, że zapytanie LINQ zawiera przetwarzanie w trybie runtime, którego tłumacz nie może przekształcić w SQL. – jrista

+0

Odpowiedziałem na twój komentarz dotyczący mojej odpowiedzi poniżej. –

+0

Czy nie ma ORDER BY? Ile wierszy mówimy i jak oceniasz, że wyniki są różne? Czy to możliwe, że zamówienie jest inne i sprawia, że ​​wygląda inaczej? –

Odpowiedz

2

Cóż, po pewnym powrocie z bardzo pomocnym przedstawicielem obsługi technicznej firmy Microsoft, w końcu dotarliśmy do źródła problemu. I niestety nie dostarczyłem wystarczającej ilości informacji w moim oryginalnym poście dla nikogo tutaj na SO, aby dokonać determinacji, więc moje przeprosiny w tym względzie.

Oto kwestia - jako część kodu, który konstruuje kwerendy LINQ w pytaniu, oświadczyłem zmienną .Net tak:

Dim RadCvtFactor As Decimal = Math.PI/180 

Okazuje się, że kiedy to przeszedł do SQL deklarację parametru , o czym świadczy plik dziennika LINQ, to DECIMAL (29, 4). Ze względu na wartość skali w deklaracji niepoprawna wartość jest przekazywana do RDBMS, co powoduje dziwną różnicę w wynikach zapytania.

Deklarując zmienną .Net jako pojedyncza wartość, tak jak poniżej:

Dim RadCvtFactor As Single = Math.PI/180 

całkowicie rozwiązuje problem.

Przedstawiciel Microsoft potwierdził, że konwersja tego parametru może być "potencjalnym problemem" i skonsultowałaby się z zespołem ds. Produktu.

Dziękuję wszystkim, którzy przesłali odpowiedzi.

1

Jedną rzeczą, która natychmiast przychodzi na myśl, jest problem z pozwoleniem. Czy jest możliwe, że program i ręcznie wykonane zapytanie działają pod różnymi poświadczeniami, a zatem mają różne poziomy dostępu do bazy danych? Może to wpłynąć na wyniki zapytania.

+0

Chociaż może to wyjaśnić brakujące wiersze, myślę, że jest wysoce nieprawdopodobne, aby ten sam wiersz wyglądał inaczej w dwóch kontekstach, chyba że zapytanie zostało celowo wykonane z wyrażeniami CASE na podstawie nazwy użytkownika. Zakładam, że jest to po prostu zapytanie SELECT, a nie wywołanie procedury przechowywanej (gdzie taka logika może być niewidoczna dla Boba Mc). –

+0

Tak, to tylko zapytanie SELECT, a nie przechowywane wywołanie proc. –

+0

Zalogowałem się do SQL Server Management Studio, używając poświadczeń programu i wypróbowałem zapytanie. Mam prawidłowe wyniki, więc uprawnienia nie wydają się być. W każdym razie dzięki. –

1

Zacznę od sprawdzenia twojego DataContext. Jeśli twój DataContext nie jest aktualizowany z SQL Server, być może zwraca starszą wersję tabeli.

DataContext utrzymuje stan bazy danych po jej utworzeniu. Chcesz używać nowego kontekstu dla każdego zestawu operacji.

+0

To dobra myśl, może spróbuj z bardzo prostą kwerendą w jednym wierszu. Zaktualizuj wiersz w bazie danych i zobacz, czy Linq się zbliża. –

+0

Kiedy przeczytałem tę odpowiedź, myślałem na pewno, że to był problem, ale zaktualizowałem odpowiednie tabele i widoki w pliku DBML bez żadnej radości. –

+0

Nie DBML, ale faktyczny tekst danych. Powinieneś robić Dim db jako context = new MyDbContext() za każdym razem, gdy wykonujesz nową operację. Jeśli MyGetDataContextHelper() tworzy wykorzystuje kontekst między wywołaniami, nie będzie pobierał najświeższej tabeli z bazy danych. –

1

Inną możliwością jest poziom izolacji i rodzaj danych. Czy używasz REPEATABLE READ lub READ UNCOMMITTED lub SNAPSHOT pod Linq? A co powiesz na używanie SSMS? Oczywiście, jeśli dane się poruszają, luźny poziom izolacji pozwoli ci pominąć wiersze, przeczytać dwa wiersze dwa razy, zobaczyć starą wersję wiersza, itp.

Czy możesz podać nam nieco lepsze pojęcie o tym, co " bardzo złożone zapytanie "wygląda jak? Nie musisz używać swoich prawdziwych nazw tabel.

+0

Zgodnie z Twoją prośbą opublikowałem skondensowaną wersję wygenerowanego zapytania z Linq. Nie jestem pewien, w jaki sposób będę używał REPEATABL READ lub READ UNCOMMITTED, czy możesz je rozwinąć? Poza tym dane są bardzo statyczne - nie jest to transakcja, a raczej raportowanie. Dzięki. –

+0

Nie używam Linq, ale rozumiem, że można jawnie ustawić poziom izolacji za pomocą czegoś takiego jak: IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted ... jednak ponieważ mówisz, że dane są względnie statyczne, nadal zgaduję że (a) zapytanie, które porównujesz, nie jest tym, które faktycznie zostało wysłane, lub (b) Twój DataContext jest nieaktualny. –

1

Możesz użyć DebuggerWriter, aby sprawdzić rzeczywisty SQL wysłany do serwera.

+0

Dzięki, już to zrobiłem, z tym samym wynikiem. To właśnie miałem na myśli w oryginalnym poście, gdy zauważyłem, że użyłem "właściwości dziennika DataContext", aby napisać do pliku. Chyba że masz na myśli coś innego. Jeśli tak, proszę wyjaśnij. –

1
qry.ToList() 

Ta instrukcja tworzy i zwraca wybraną listę. Musisz przypisać wynik do czegoś (np. Zmienna lokalna), jeśli chcesz później skorzystać z listy.

Edytuj: dzięki za aktualizację.

Podejrzewam, że to musi być coś nie jesteś z nami informacją, że może być również problem i może żyć tutaj:

Dim db as MyDataContext = MyGetDataContextHelper() 

Czy ta metoda łączenia do tej samej bazie danych jako ten, który podłączony do kiedy użyłeś sql studio?

  • Sprawdź właściwość Connection datacontext.
  • Upewnij się, że zapytanie jest wysyłane do bazy danych, obserwując to za pomocą programu profilującego sql.
  • Wydanie bardzo prostego zapytania i potwierdzenie, że zwraca poprawne wyniki.
+0

Mój kod powinien mieć wartość Return qry.ToList(), ponieważ fragment kodu jest częścią funkcji zwracającej listę. Zmodyfikowałem kod, aby to odzwierciedlić. –

1

Może wydawać się głupie, ale zawsze dobrze sprawdzić, czy łączysz się z tym samym środowiskiem baz danych w systemie SSMS, z którego pochodzi aplikacja? :)