Ste*_*a D 12 c# entity-framework sql-server-2012 entity-framework-6
背景
我正在编写一个应用程序,它可以在邮政编码的某个半径范围内查找事件.您可以将其视为售票员,您可以在其中输入您的邮政编码,并显示半径为x的所有音乐会.
我有一个数据库表,其中包含邮政编码,每个邮政编码都有"纬度和经度".我还有一个'EventListings'表,其中每个'Event'都有一个ZipCode字段.
问题
目前,我在服务层的Linq-to-Entities查询中使用Haversine公式来查找哪些事件在半径范围内.现在,我将它用作where子句中的过滤器.我也想把它放在select子句中,所以我可以在网站上显示"这距离4.6英里",等等.
我无法将此代码移动到单独的C#方法中,因为Linq-to-Entities会抱怨它无法将其转换为sql,因此我也会在select语句中复制整个公式.这非常难看.我试着解决它.
我试过的
我编辑了Entity,并添加了一个特殊的标量属性"DistanceFromOrigin".然后,我创建了一个存储过程,它返回了所有实体数据,以及新字段"DistanceFromOrigin"的硬编码值(用于测试目的).
然后我才意识到我无法告诉实体框架在EventListings实体上使用我的sproc作为其select语句...... Phil提出了spatials,这就是我的用法.
题
如何使用Spatials搜索邮政编码范围内的事件?
Ste*_*a D 22
所以,使用菲尔的建议,我用空间重新写了很多这个.这很好,你只需要.NET4.5,EF5 +和sql server(我相信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);
Run Code Online (Sandbox Code Playgroud)
距离扩展方法获取从当前对象到您传入的"其他"对象的距离.此另一个对象属于类型DbGeography.你只需要调用静态方法,然后创建其中一只小狗,然后将经度和纬度作为一个点:
DBGeography originCoordinates = DBGeography.fromText("Point(" + originLongitude + " " + originLatitude + ")");
Run Code Online (Sandbox Code Playgroud)
这不是我创建originCoordinates的方式.我下载了一个单独的数据库,其中包含所有邮政编码及其纬度和经度的列表.我也添加了一个类型的列Geography.我将在这个答案结尾处展示.然后,我查询了zipcode上下文,以从ZipCode表中的Location字段获取DbGeography对象.
如果用户需要比邮政编码更具体的来源,我会调用Google Maps API(GeoCode更具体)并通过Web服务获取用户特定地址的纬度和经度,并从中创建DBGeography对象响应中的纬度和经度值.
我也在创建活动时使用谷歌API.在将我的实体添加到EF之前,我只是设置了这样的位置变量:
someEventEntity.Location = DBGeography.fromText("Point(" + longitudeFromGoogle+ " " + latitudeFromGoogle + ")");
Run Code Online (Sandbox Code Playgroud)
我是如何获得距离扩展方法的?
要获得扩展方法Distance,必须添加对项目的引用:System.Data.Entity
执行此操作后,必须将using:添加using System.Data.Entity.Spatial;到您的类中.
该Distance扩展方法返回一个距离的米计量单位(你可以改变它,我认为,但是这是默认值).在这里,我的半径参数是英里,所以我做了一些数学转换.
注意:有一个DBGeography班级System.Data.Spatial.这是错误的,它对我不起作用.我在互联网上找到的很多例子都使用了这个例子.
如何将Lat/Long转换为Geography Column
所以,如果你像我一样下载了包含所有Latitude&Longitude列的邮政编码数据库,然后意识到它没有地理列......这可能会有所帮助:
1)在表格中添加"位置"列.将类型设置为Geography.
2)执行以下sql
UPDATE [ZipCodes]
SET Location = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + CAST([Latitude] AS VARCHAR(20)) + ')', 4326)
Run Code Online (Sandbox Code Playgroud)
如何查看地理项目的详细信息
因此,当您在插入一些DbGeography项后查询Sql Server Management Studio中的EventListings表时,您将看到该Location列包含十六进制值,如:0x1234513462346.如果要确保插入正确的值,这不是很有用.
要实际查看此字段的纬度和经度,您必须如下查询:
SELECT Location.Lat Latitude, Location.Long Longitude
FROM [EventListings]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2286 次 |
| 最近记录: |