sql >> Base de Datos >  >> RDS >> Sqlserver

¿Cómo uso los espacios para buscar un radio de códigos postales?

Entonces, usando la sugerencia de Phil, reescribí mucho de esto usando espaciales. Esto funcionó muy bien, solo necesita .NET4.5, EF5 + y el servidor sql (2008 y superior, creo). Estoy usando EF6 + Sql Server 2012.

Configuración

El primer paso fue agregar una Geography columna a mi base de datos EventListings tabla (clic derecho sobre ella -> Diseño). Llamé a la mía Ubicación:

Luego, dado que estoy usando el EDM con la base de datos primero, tuve que actualizar mi modelo para usar el nuevo campo que creé. Luego recibí un error sobre no poder convertir Geografía a doble, así que lo que hice para solucionarlo fue seleccionar la propiedad Ubicación en la entidad, ir a sus propiedades y cambiar su tipo de doble a Geography :

Consultar dentro de un radio y agregar eventos con ubicaciones

Entonces todo lo que tiene que hacer es consultar su colección de entidades de esta manera:

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

El método de extensión Distancia obtiene la distancia desde el objeto actual hasta el "otro" objeto que pasa. Este otro objeto es del tipo DbGeography . Simplemente llama a un método estático y crea uno de estos cachorros, luego simplemente agrega su Longitud y Latitud como un punto:

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

No es así como creé mis coordenadas de origen. Descargué una base de datos separada que tenía una lista de todos los códigos postales y sus Latitudes y Longitudes. Agregué una columna de tipo Geography a eso también. Mostraré cómo al final de esta respuesta. Luego consulté el contexto del código postal para obtener un objeto DbGeography del campo Ubicación en la tabla ZipCode.

Si el usuario quiere un origen más específico que solo un código postal, realizo una llamada a la API de Google Maps (GeoCode para ser más específico) y obtengo la latitud y longitud de la dirección específica del usuario a través de un servicio web, y creo un objeto DBGeography a partir de los valores de Latitud y Longitud en la respuesta.

También uso las API de Google cuando creo un evento. Acabo de configurar la variable de ubicación de esta manera antes de agregar mi entidad a EF:

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

Otros consejos, trucos y solución de problemas

¿Cómo obtuve el método de extensión de distancia?

Para obtener el método de extensión Distance debe agregar una referencia a su proyecto:System.Data.Entity Después de hacer eso, debe agregar el uso:using System.Data.Entity.Spatial; a tu clase

La Distance el método de extensión devuelve la distancia con una unidad de medida de metros (Creo que puede cambiarlo, pero esto es predeterminado). Aquí, mi parámetro de radio estaba en millas, así que hice algunos cálculos para convertir.

Nota :Hay una DBGeography clase en System.Data.Spatial . Este es el equivocado y no me funcionaria. Muchos ejemplos que encontré en Internet usaban este.

Cómo convertir Lat/Long a Columna Geográfica

Entonces, si fuera como yo y descargara una base de datos de códigos postales con todos los Latitude &Longitude columnas, y luego me di cuenta de que no tenía una columna de Geografía... esto podría ayudar:

1) Agregue una columna de Ubicación a su tabla. Establezca el tipo en Geografía.

2) Ejecute el siguiente sql

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

Cómo ver los detalles de un elemento de Geografía

Entonces, cuando consulte su tabla EventListings en Sql Server Management Studio después de haber insertado algunos elementos de DbGeography, verá la Location columna tiene un valor hexadecimal como:0x1234513462346. Esto no es muy útil cuando desea asegurarse de que se insertaron los valores correctos.

Para ver realmente la latitud y la longitud de este campo, debe consultarlo así:

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