Takže na základě Philova návrhu jsem mnoho z toho přepsal pomocí prostorových. To fungovalo skvěle, potřebujete jen .NET4.5, EF5+ a sql server (věřím, že 2008 a vyšší). Používám EF6 + SQL Server 2012.
Nastavení
Prvním krokem bylo přidat Geography
sloupec do mé databáze EventListings
tabulka (klikněte na ni pravým tlačítkem -> Návrh). Své umístění jsem pojmenoval:
Dále, protože používám EDM s databází-first, musel jsem aktualizovat svůj model, aby používal nové pole, které jsem vytvořil. Pak se mi zobrazila chyba o nemožnosti převést Geografii na dvojitou, takže jsem to opravil tak, že jsem v entitě vybral vlastnost Location, přešel do jejích vlastností a změnil její typ z double na Geography
:
Dotazování v rámci okruhu a přidávání událostí s místy
Pak vše, co musíte udělat, je dotazovat se na kolekci entit takto:
var events = EventRepository.EventListings
.Where(x => x.Location.Distance(originCoordinates) * 0.00062 <= radiusParam);
Metoda Distance extension získává vzdálenost od aktuálního objektu k „jinému“ objektu, který předáte. Tento další objekt je typu DbGeography
. Stačí zavolat statickou metodu a ta vytvoří jedno z těchto štěňat, pak do ní stačí umístit svou zeměpisnou délku a šířku jako bod:
DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");
Takto jsem nevytvořil své původní souřadnice. Stáhl jsem si samostatnou databázi, která měla seznam všech PSČ a jejich zeměpisné šířky a délky. Přidal jsem sloupec typu Geography
k tomu také. Jak na to ukážu na konci této odpovědi. Poté jsem se zeptal na kontext PSČ, abych získal objekt DbGeography z pole Location v tabulce PSČ.
Pokud uživatel chce konkrétnější původ než jen PSČ, zavolám rozhraní Google Maps API (přesněji GeoCode) a prostřednictvím webové služby získám zeměpisnou šířku a délku pro konkrétní adresu uživatele a vytvořím objekt DBGeography z hodnoty zeměpisné šířky a délky v odpovědi.
Při vytváření události také používám rozhraní Google API. Před přidáním své entity do EF jsem nastavil proměnnou umístění takto:
someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");
Další tipy a triky a odstraňování problémů
Jak jsem získal metodu prodlužování vzdálenosti?
Chcete-li získat metodu rozšíření Distance
musíte přidat odkaz na svůj projekt:System.Data.Entity
Poté musíte přidat pomocí:using System.Data.Entity.Spatial;
do vaší třídy.
Distance
metoda rozšíření vrací vzdálenost s měrnou jednotkou metrů (Myslím, že to můžete změnit, ale toto je výchozí). Zde byl můj parametr poloměru v mílích, takže jsem pro převod provedl nějaké výpočty.
Poznámka :Existuje DBGeography
třídy v System.Data.Spatial
. Toto je špatný a to by mi nefungovalo. Mnoho příkladů, které jsem našel na internetu, použilo tento.
Jak převést Lat/Long na Geografický sloupec
Takže pokud jste byli jako já a stáhli jste si databázi PSČ se všemi Latitude
&Longitude
a pak si uvědomil, že nemá sloupec Zeměpis... to by mohlo pomoci:
1) Přidejte do tabulky sloupec Umístění. Nastavte typ na Geografie.
2) Spusťte následující sql
UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)
Jak zobrazit podrobnosti o položce Zeměpis
Když tedy zadáte dotaz na tabulku EventListings v Sql Server Management Studio poté, co jste vložili nějaké položky DbGeography, uvidíte Location
sloupec obsahuje hexadecimální hodnotu jako:0x1234513462346. To není příliš užitečné, když se chcete ujistit, že byly vloženy správné hodnoty.
Chcete-li skutečně zobrazit zeměpisnou šířku a délku mimo toto pole, musíte se dotázat takto:
SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]