Så ved at bruge Phils forslag, omskrev jeg meget af dette ved hjælp af rumlige elementer. Dette fungerede godt, du skal bare bruge .NET4.5, EF5+ og sql server (2008 og derover, tror jeg). Jeg bruger EF6 + SQL Server 2012.
Opsætning
Det første skridt var at tilføje en Geography
kolonne til min database EventListings
tabel (Højreklik på den -> Design). Jeg navngav min placering:
Dernæst, da jeg bruger EDM med database-first, var jeg nødt til at opdatere min model for at bruge det nye felt, som jeg oprettede. Så modtog jeg en fejl om, at jeg ikke kunne konvertere Geography til double, så det, jeg gjorde for at rette det, var at vælge Location-egenskaben i entiteten, gå til dens egenskaber og ændre dens type fra double til Geography
:
Forespørgsel inden for en radius og tilføjelse af begivenheder med placeringer
Så skal du bare forespørge på din enhedssamling på denne måde:
var events = EventRepository.EventListings
.Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam);
Afstandsudvidelsesmetoden henter afstanden fra det aktuelle objekt til det "andet" objekt, som du passerer ind. Dette andet objekt er af typen DbGeography
. Du kalder bare en statisk metode, og den skaber en af disse hvalpe, så smid bare din længde- og breddegrad i den som et punkt:
DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");
Det er ikke sådan, jeg oprettede mine originCoordinates. Jeg downloadede en separat database, der havde en liste over alle postnumre og deres breddegrader og længdegrader. Jeg tilføjede en kolonne af typen Geography
også til det. Jeg viser hvordan i slutningen af dette svar. Jeg forespurgte derefter postnummerkonteksten for at få et DbGeography-objekt fra feltet Placering i postkodetabellen.
Hvis brugeren ønsker en mere specifik oprindelse end blot et postnummer, ringer jeg til Google Maps API (GeoCode for at være mere specifik) og får bredde- og længdegraden for brugerens specifikke adresse via en webservice, og opretter et DBGeography objekt fra værdierne for breddegrad og længdegrad i svaret.
Jeg bruger også Google API'er, når jeg opretter en begivenhed. Jeg indstillede bare placeringsvariablen sådan her, før jeg tilføjede min enhed til EF:
someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");
Andre tips og tricks og fejlfinding
Hvordan fik jeg metoden til afstandsforlængelse?
For at få udvidelsesmetoden Distance
du skal tilføje en reference til dit projekt:System.Data.Entity
Når du har gjort det, skal du tilføje ved hjælp af:using System.Data.Entity.Spatial;
til din klasse.
Distance
forlængelsesmetoden returnerer afstanden med en måleenhed meter (Du kan ændre det tror jeg, men dette er standard). Her var min radiusparameter i miles, så jeg lavede noget matematik for at konvertere.
Bemærk :Der er en DBGeography
klasse i System.Data.Spatial
. Dette er den forkerte og det ville ikke virke for mig. Mange eksempler, jeg fandt på internettet, brugte denne.
Sådan konverteres Lat/Long til Geografi-kolonne
Så hvis du var ligesom mig og downloadede en postnummerdatabase med alle Latitude
&Longitude
kolonner, og indså så, at den ikke havde en Geografi-kolonne... dette kunne måske hjælpe:
1) Tilføj en placeringskolonne til din tabel. Indstil typen til Geografi.
2) Udfør følgende sql
UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)
Sådan får du vist detaljerne for et geografielement
Så når du forespørger på din EventListings-tabel i SQL Server Management Studio, efter at du har indsat nogle DbGeography-elementer, vil du se Location
kolonne indeholder en hex-værdi som:0x1234513462346. Dette er ikke særlig nyttigt, når du vil sikre dig, at de korrekte værdier er indsat.
For faktisk at se bredde- og længdegraden ud af dette felt skal du forespørge på det sådan:
SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]