Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Come faccio a utilizzare spazial per cercare un raggio di codici postali?

Quindi, usando il suggerimento di Phil, ho riscritto molto di questo usando spaziali. Ha funzionato alla grande, hai solo bisogno di .NET4.5, EF5+ e sql server (credo dal 2008 in poi). Sto usando EF6 + SQL Server 2012.

Impostazione

Il primo passo è stato aggiungere una Geography colonna al mio database EventListings tabella (fai clic destro su di essa -> Design). Ho chiamato la mia Località:

Successivamente, poiché sto utilizzando l'EDM con il database prima, ho dovuto aggiornare il mio modello per utilizzare il nuovo campo che ho creato. Quindi ho ricevuto un errore relativo all'impossibilità di convertire Geografia in double, quindi quello che ho fatto per risolverlo è stato selezionare la proprietà Posizione nell'entità, andare alle sue proprietà e cambiarne il tipo da double a Geography :

Interrogazione entro un raggio e aggiunta di eventi con posizioni

Quindi tutto ciò che devi fare è interrogare la tua raccolta di entità in questo modo:

 var events = EventRepository.EventListings
                             .Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam); 

Il metodo di estensione della distanza ottiene la distanza dall'oggetto corrente, all'"altro" oggetto in cui si passa. Quest'altro oggetto è di tipo DbGeography . Chiama semplicemente un metodo statico e crea uno di questi cuccioli, quindi inserisci la tua longitudine e latitudine come punto:

DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");

Non è così che ho creato le mie OriginCoordinates. Ho scaricato un database separato che conteneva un elenco di tutti i codici postali e le loro latitudini e longitudini. Ho aggiunto una colonna di tipo Geography anche a quello. Mostrerò come alla fine di questa risposta. Ho quindi interrogato il contesto del codice postale per ottenere un oggetto DbGeography dal campo Posizione nella tabella Codice postale.

Se l'utente desidera un'origine più specifica rispetto a un semplice codice postale, faccio una chiamata all'API di Google Maps (GeoCode per essere più specifici) e ottengo la latitudine e la longitudine per l'indirizzo specifico dell'utente tramite un servizio web e creo un oggetto DBGeography da i valori di latitudine e longitudine nella risposta.

Uso anche le API di Google quando creo un evento. Ho appena impostato la variabile di posizione in questo modo prima di aggiungere la mia entità a EF:

someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");

Altri suggerimenti, trucchi e risoluzione dei problemi

Come ho ottenuto il metodo di estensione della distanza?

Per ottenere il metodo di estensione Distance devi aggiungere un riferimento al tuo progetto:System.Data.Entity Dopo averlo fatto, devi aggiungere using:using System.Data.Entity.Spatial; alla tua classe

La Distance metodo di estensione restituisce la distanza con un'unità di misura dei metri (Puoi cambiarlo credo, ma questo è predefinito). Qui, il mio parametro del raggio era in miglia, quindi ho fatto dei calcoli per convertire.

Nota :C'è un DBGeography classe in System.Data.Spatial . Questo è quello sbagliato e non funzionerebbe per me. Molti esempi che ho trovato su Internet hanno usato questo.

Come convertire Lat/Long in Colonna Geografia

Quindi, se tu fossi come me e scaricassi un database di codici postali con tutto il Latitude &Longitude colonne, e poi ho capito che non aveva una colonna Geografia... questo potrebbe aiutare:

1) Aggiungi una colonna Posizione alla tua tabella. Imposta il tipo su Geografia.

2) Esegui il seguente sql

UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)

Come visualizzare i dettagli di un elemento Geografia

Quindi, quando esegui una query sulla tabella EventListings in Sql Server Management Studio dopo aver inserito alcuni elementi di DbGeography, vedrai il Location la colonna contiene un valore esadecimale come:0x1234513462346. Questo non è molto utile quando vuoi assicurarti che siano stati inseriti i valori corretti.

Per visualizzare effettivamente la latitudine e la longitudine fuori da questo campo, devi interrogarlo in questo modo:

SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]