如何使用空格搜索郵政編碼的半徑?

c# entity-framework entity-framework-6 sql-server-2012

背景

我正在編寫一個應用程序,它可以在郵政編碼的某個半徑範圍內查找事件。您可以將其視為票務管理員,您可以在其中輸入您的郵政編碼,並顯示半徑為x的所有音樂會。

我有一個數據庫表,其中包含郵政編碼,每個郵政編碼都有“緯度和經度”。我還有一個'EventListings'表,其中每個'Event'都有一個ZipCode字段。

問題

目前,我在服務層的Linq-to-Entities查詢中使用Haversine公式來查找哪些事件在半徑範圍內。現在,我將它用作where子句中的過濾器。我也想把它放在select子句中,所以我可以在網站上顯示“這距離4.6英里”,等等。

我無法將此代碼移動到單獨的C#方法中,因為Linq-to-Entities會抱怨它無法將其轉換為sql,因此我也會在select語句中復制整個公式。這非常難看。我試著解決它。

我試過的

我編輯了Entity,並添加了一個特殊的標量屬性“DistanceFromOrigin”。然後,我創建了一個存儲過程,它返回了所有實體數據,以及新字段“DistanceFromOrigin”的硬編碼值(用於測試目的)。

然後我開始意識到我不能告訴實體框架使用我的sproc在EventListings實體上的select語句...... Phil提出了spatials,這就是我的意思。

如何使用Spatials搜索郵政編碼範圍內的事件?

一般承認的答案

所以,使用菲爾的建議,我用空間重新寫了很多這個。這很好,你只需要.NET4.5,EF5 +和sql server(我相信2008年及以上)。我正在使用EF6 + Sql Server 2012。

建立

第一步是將Geography列添加到我的數據庫EventListings表(右鍵單擊它 - > Design)。我命名我的位置:

在此處輸入圖像描述

接下來,由於我首先使用EDM和數據庫,我不得不更新我的模型以使用我創建的新字段。然後我收到一個關於無法將Geography轉換為double的錯誤,所以我要解決的是選擇實體中的Location屬性,轉到其屬性並將其類型從double更改為Geography

在此處輸入圖像描述

在半徑內查詢並使用位置添加事件

然後你要做的就是查詢你的實體集合,如下所示:

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

距離擴展方法獲取從當前對像到您傳入的“其他”對象的距離。此另一個對象的類型為DbGeography 。你只需要調用靜態方法,然後創建其中一隻小狗,然後將經度和緯度作為一個點:

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

這不是我創建originCoordinates的方式。我下載了一個單獨的數據庫,其中包含所有郵政編碼及其緯度和經度的列表。我也添加了一個Geography類型的列。我將在這個答案的最後給出。然後,我查詢了zipcode上下文,以從ZipCode表中的Location字段獲取DbGeography對象。

如果用戶需要比郵政編碼更具體的來源,我會調用Google Maps API(更具體的GeoCode)並通過Web服務獲取用戶特定地址的緯度和經度,並從中創建DBGeography對象響應中的緯度和經度值。

我也在創建活動時使用谷歌API。在將實體添加到EF之前,我只是設置了這樣的位置變量:

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

其他提示與技巧和疑難解答

我是如何獲得距離擴展方法的?

要獲取擴展方法Distance ,必須添加對項目的引用: System.Data.Entity執行此操作後,必須添加using: using System.Data.Entity.Spatial;到你的班級。

Distance擴展方法以米單位返回距離(您可以更改它,但這是默認值)。這裡,我的半徑參數是英里,所以我做了一些數學轉換。

注意System.Data.Spatial有一個DBGeography類。這是錯誤的 ,它對我不起作用。我在互聯網上找到的很多例子都使用了這個例子。

如何將Lat / Long轉換為Geography Column

所以,如果你像我一樣下載了一個包含所有LatitudeLongitude列的郵政編碼數據庫,然後意識到它沒有地理列......這可能會有所幫助:

1)在表格中添加“位置”列。將類型設置為Geography。

2)執行以下sql

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

如何查看地理項目的詳細信息

因此,當您在插入一些DbGeography項後查詢Sql Server Management Studio中的EventListings表時,您將看到Location列包含十六進制值,如:0x1234513462346。當您想確保插入正確的值時,這不是很有用。

要實際查看此字段的緯度和經度,您必須像這樣查詢:

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


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因