И така, използвайки предложението на Фил, пренаписах много от това, използвайки пространствени знаци. Това се получи страхотно, просто ви трябват .NET4.5, EF5+ и sql сървър (2008 и по-нова версия, вярвам). Използвам EF6 + Sql Server 2012.
Настройка
Първата стъпка беше да добавите Geography
колона към моята база данни EventListings
таблица (Щракнете с десния бутон върху нея -> Дизайн). Нарекох моето местоположение:
След това, тъй като използвам EDM с първо базата данни, трябваше да актуализирам модела си, за да използвам новото поле, което създадох. След това получих грешка, че не мога да конвертирам Geography в double, така че това, което направих, за да го поправя, беше да избера свойството Location в обекта, да отида до неговите свойства и да променя типа му от double на Geography
:
Заявки в рамките на радиус и добавяне на събития с местоположения
След това всичко, което трябва да направите, е да направите запитване към вашата колекция от обекти по следния начин:
var events = EventRepository.EventListings
.Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam);
Методът за разширение Distance получава разстоянието от текущия обект до „другия“ обект, който подавате. Този друг обект е от тип DbGeography
. Просто извиквате статичен метод и той създава едно от тези кученца, след което просто добавяте вашата дължина и ширина в него като точка:
DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");
Това не е начинът, по който създадох моите originCoordinates. Изтеглих отделна база данни, която имаше списък на всички пощенски кодове и техните географски ширини и дължини. Добавих колона от тип Geography
към това също. Ще покажа как в края на този отговор. След това направих заявка за контекста на пощенския код, за да получа обект DbGeography от полето Location в таблицата ZipCode.
Ако потребителят иска по-конкретен произход от просто пощенски код, аз се обаждам на API на Google Maps (GeoCode, за да бъдем по-конкретни) и получавам географската ширина и дължина за конкретния адрес на потребителя чрез уеб услуга и създавам DBGeography обект от стойностите за географска ширина и дължина в отговора.
Използвам API на Google и когато създавам събитие. Току-що зададох променливата за местоположение по този начин, преди да добавя моя обект към EF:
someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");
Други съвети и трикове и отстраняване на неизправности
Как получих метода за удължаване на разстоянието?
За да получите метода на разширение Distance
трябва да добавите препратка към вашия проект:System.Data.Entity
След като направите това, трябва да добавите using:using System.Data.Entity.Spatial;
към вашия клас.
Distance
методът за разширение връща разстоянието с мерна единица метри (Мисля, че можете да го промените, но това е по подразбиране). Тук моят параметър за радиус беше в мили, така че направих малко математика, за да конвертирам.
Забележка :Има DBGeography
клас в System.Data.Spatial
. Това егрешният и нямаше да работи за мен. Много примери, които намерих в интернет, използваха този.
Как да конвертирате ширина/дължина в географска колона
И така, ако бяхте като мен и изтеглихте база данни с пощенски кодове с всички 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]