Dus, gebruikmakend van de suggestie van Phil, heb ik veel hiervan herschreven met behulp van ruimtelijke gegevens. Dit werkte prima, je hebt alleen .NET4.5, EF5+ en sql-server nodig (2008 en hoger geloof ik). Ik gebruik EF6 + SQL Server 2012.
Configuratie
De eerste stap was het toevoegen van een Geography
kolom naar mijn database EventListings
tabel (klik er met de rechtermuisknop op -> Ontwerp). Ik noemde de mijne Locatie:
Vervolgens, aangezien ik de EDM eerst met database gebruik, moest ik mijn model bijwerken om het nieuwe veld te gebruiken dat ik heb gemaakt. Toen kreeg ik een foutmelding over het niet kunnen converteren van geografie naar dubbel, dus wat ik deed om het op te lossen, was de locatie-eigenschap in de entiteit selecteren, naar de eigenschappen gaan en het type wijzigen van dubbel in Geography
:
Query binnen een straal en evenementen toevoegen met locaties
Het enige wat u hoeft te doen, is uw entiteitsverzameling als volgt opvragen:
var events = EventRepository.EventListings
.Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam);
De Distance extension-methode haalt de afstand van het huidige object naar het "andere" object dat u doorgeeft. Dit andere object is van het type DbGeography
. Je roept gewoon een statische methode aan en het creëert een van deze puppy's, gooi dan gewoon je lengte- en breedtegraad erin als een punt:
DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");
Dit is niet hoe ik mijn originCoordinates heb gemaakt. Ik heb een aparte database gedownload met een lijst van alle postcodes en hun breedte- en lengtegraden. Ik heb een kolom van het type Geography
toegevoegd daar ook naar. Ik zal laten zien hoe aan het einde van dit antwoord. Vervolgens heb ik de postcodecontext opgevraagd om een DbGeography-object te krijgen uit het veld Location in de ZipCode-tabel.
Als de gebruiker een meer specifieke oorsprong wil dan alleen een postcode, bel ik de Google Maps API (GeoCode om specifieker te zijn) en krijg ik de breedte- en lengtegraad voor het specifieke adres van de gebruiker via een webservice en maak ik een DBGeography-object van de breedte- en lengtegraadwaarden in het antwoord.
Ik gebruik ook Google API's wanneer ik een evenement maak. Ik heb de locatievariabele zo ingesteld voordat ik mijn entiteit aan EF toevoeg:
someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");
Andere tips en trucs en probleemoplossing
Hoe ben ik aan de Distance Extension-methode gekomen?
Om de extensiemethode Distance
te krijgen u moet een verwijzing naar uw project toevoegen:System.Data.Entity
Nadat je dat hebt gedaan, moet je het gebruik toevoegen:using System.Data.Entity.Spatial;
naar je klas.
De Distance
extension method retourneert de afstand met een maateenheid (Je kunt het veranderen denk ik, maar dit is standaard). Hier was mijn straalparameter in mijlen, dus ik heb wat rekenwerk gedaan om te converteren.
Opmerking :Er is een DBGeography
klasse in System.Data.Spatial
. Dit is de verkeerde en bij mij zou het niet werken. Veel voorbeelden die ik op internet vond, gebruikten deze.
Lat/Long converteren naar geografiekolom
Dus, als je net als ik was en een postcodedatabase downloadde met alle Latitude
&Longitude
kolommen, en realiseerde zich toen dat het geen kolom Aardrijkskunde had... dit zou kunnen helpen:
1) Voeg een kolom Locatie toe aan uw tabel. Stel het type in op Geografie.
2) Voer de volgende sql uit
UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)
De details van een geografie-item bekijken
Dus wanneer u uw EventListings-tabel opvraagt in Sql Server Management Studio nadat u enkele DbGeography-items heeft ingevoegd, ziet u de Location
kolom bevat een hexadecimale waarde zoals:0x1234513462346. Dit is niet erg handig als u er zeker van wilt zijn dat de juiste waarden zijn ingevoegd.
Om de breedte- en lengtegraad daadwerkelijk buiten dit veld te bekijken, moet u het als volgt opvragen:
SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]