Tak więc, korzystając z sugestii Phila, wiele z nich napisałem na nowo, używając przestrzenności. Udało się to świetnie, potrzebujesz tylko serwera .NET4.5, EF5 + i sql (wydaje mi się, że 2008 i nowsze). Używam EF6 + SQL Server 2012.
Konfiguracja
Pierwszym krokiem było dodanie Geography
kolumna do mojej bazy danych EventListings
tabela (kliknij prawym przyciskiem myszy -> Projekt). Nazwałem moją lokalizację:
Następnie, ponieważ używam EDM z bazą danych, musiałem zaktualizować mój model, aby używał nowego pola, które stworzyłem. Następnie otrzymałem błąd dotyczący niemożności przekonwertowania geografii na double, więc naprawiłem to, wybierając właściwość Location w encji, przechodząc do jej właściwości i zmieniając jej typ z double na Geography
:
Zadawanie zapytań w promieniu i dodawanie zdarzeń z lokalizacjami
Następnie wszystko, co musisz zrobić, to wysłać zapytanie do swojej kolekcji encji w następujący sposób:
var events = EventRepository.EventListings
.Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam);
Metoda rozszerzenia Distance pobiera odległość od bieżącego obiektu do „innego” obiektu, który przekazujesz. Ten inny obiekt jest typu DbGeography
. Po prostu wywołujesz metodę statyczną i tworzy jednego z tych szczeniąt, a następnie po prostu wrzucasz do niej swoją długość i szerokość geograficzną jako punkt:
DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");
Nie tak utworzyłem moje originCoordinates. Pobrałem osobną bazę danych, która zawierała listę wszystkich kodów pocztowych oraz ich szerokości i długości geograficznej. Dodałem kolumnę typu Geography
do tego również. Pokażę jak na końcu tej odpowiedzi. Następnie zapytałem kontekst kodu pocztowego, aby uzyskać obiekt DbGeography z pola Location w tabeli ZipCode.
Jeśli użytkownik chce bardziej szczegółowego pochodzenia niż tylko kod pocztowy, wywołuję Google Maps API (GeoCode by być bardziej szczegółowym) i pobieram szerokość i długość geograficzną dla konkretnego adresu użytkownika za pośrednictwem usługi sieciowej i tworzę obiekt DBGeography z wartości szerokości i długości geograficznej w odpowiedzi.
Używam interfejsów Google API podczas tworzenia wydarzenia. Po prostu ustawiłem zmienną lokalizacji w ten sposób przed dodaniem mojej jednostki do EF:
someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");
Inne porady i wskazówki oraz rozwiązywanie problemów
Jak zdobyłem metodę przedłużenia odległości?
Aby uzyskać metodę rozszerzenia Distance
musisz dodać referencję do swojego projektu:System.Data.Entity
Po wykonaniu tej czynności musisz dodać using:using System.Data.Entity.Spatial;
do swojej klasy.
Distance
metoda rozszerzenia zwraca odległość z jednostką miary w metrach (Myślę, że możesz to zmienić, ale to jest domyślne). Tutaj mój parametr promienia był w milach, więc zrobiłem trochę matematyki, aby przekonwertować.
Uwaga :Istnieje DBGeography
klasa w System.Data.Spatial
. To jest niewłaściwy i to by nie zadziałało dla mnie. Wiele przykładów, które znalazłem w Internecie, używało tego.
Jak przekonwertować szerokość/długość na kolumnę geograficzną
Tak więc, gdybyś był podobny do mnie i pobrał bazę danych kodów pocztowych ze wszystkimi Latitude
&Longitude
kolumn, a potem zdałem sobie sprawę, że nie ma kolumny Geografia... to może pomóc:
1) Dodaj do tabeli kolumnę Lokalizacja. Ustaw typ na Geografia.
2) Wykonaj następujący sql
UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)
Jak wyświetlić szczegóły elementu geograficznego
Tak więc, gdy wysyłasz zapytanie do tabeli EventListings w Sql Server Management Studio po wstawieniu niektórych elementów DbGeography, zobaczysz Location
kolumna zawiera wartość szesnastkową, taką jak:0x1234513462346. Nie jest to zbyt pomocne, gdy chcesz się upewnić, że wstawiono prawidłowe wartości.
Aby faktycznie wyświetlić szerokość i długość geograficzną poza tym polem, musisz zapytać o to w następujący sposób:
SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]