Ответ 1
Итак, используя предложение Фила, я переписал много всего этого с помощью пространств. Это получилось отлично, вам просто нужны .NET4.5, EF5 + и sql-сервер (2008 и выше, я считаю). Я использую EF6 + Sql Server 2012.
Set-Up
Первым шагом было добавить столбец Geography
в мою базу данных EventListings
(щелкните правой кнопкой мыши по ней → Дизайн). Я назвал мое Место:
Далее, поскольку я использую EDM с базой данных - сначала мне пришлось обновить мою модель, чтобы использовать новое поле, которое я создал. Затем я получил ошибку в том, что я не смог преобразовать географию в двойную, поэтому я исправил ее, выбрав свойство Location в объекте, перейдите к его свойствам и измените его тип с двойного на Geography
:
Запрос в радиусе и добавление событий с местоположением
Затем все, что вам нужно сделать, - это запросить коллекцию объектов следующим образом:
var events = EventRepository.EventListings
.Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam);
Метод расширения расстояния получает расстояние от текущего объекта до объекта "другого", который вы передаете. Этот другой объект имеет тип DbGeography
. Вы просто вызываете статический метод, и он создает одного из этих щенков, а затем просто бросайте в него свою долготу и широту как точку:
DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");
Это не то, как я создал свой исходный код. Я загрузил отдельную базу данных, в которой был список всех почтовых индексов и их широты и долготы. Я добавил к этому столбцу тип Geography
. Я покажу, как в конце этого ответа. Затем я запросил контекст zipcode, чтобы получить объект DbGeography из поля Location в таблице ZipCode.
Если пользователю требуется более конкретное происхождение, а не только почтовый индекс, я обращаюсь к API Карт Google (более конкретно к GeoCode) и получаю широту и долготу для конкретного адреса пользователя через веб-службу и создаю Объект DBGeography из значений широты и долготы в ответе.
Я использую API Google при создании события. Я просто установил переменную местоположения, как это, прежде чем добавить мою сущность в EF:
someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");
Другие советы и рекомендации и устранение неполадок
Как я получил метод расширения расстояния?
Чтобы получить метод расширения Distance
, вы должны добавить ссылку на свой проект: System.Data.Entity
После этого вы должны добавить в свой класс: using System.Data.Entity.Spatial;
.
Метод расширения Distance
возвращает расстояние с помощью единицы измерения метров (вы можете изменить его, я думаю, но это значение по умолчанию). Здесь мой параметр радиуса находился в милях, поэтому я сделал некоторую математику для преобразования.
Примечание. В System.Data.Spatial
есть класс DbGeography
. Это неправильный, и это не сработает для меня. Множество примеров, которые я нашел в Интернете, использовали это.
Как преобразовать столбцы Lat/Long в столбцы географии
Итак, если вы были похожи на меня и загрузили базу данных zipcode со всеми столбцами Latitude
и Longitude
, а затем поняли, что у нее нет столбца География... это может помочь:
1) Добавьте столбец местоположения в таблицу. Установите тип в Географию.
2) Выполните следующий sql
UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)
Как просмотреть детали объекта географии
Итак, когда вы запрашиваете таблицу EventListings в Sql Server Management Studio после того, как вы вставили некоторые элементы DbGeography, вы увидите, что столбец Location
содержит шестнадцатеричное значение, подобное: 0x1234513462346. Это не очень полезно, если вы хотите убедиться, что правильные значения вставлены.
Чтобы просмотреть широту и долготу этого поля, вы должны запросить его так:
SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]