查询 ASP.NET Core 2 和 Entity Framework Core 2 中表中附近的位置

Dav*_*vid 2 c# asp.net entity-framework geocoding asp.net-core-2.0

我正在尝试进行查询,在其中可以找到 SQL 数据库中给定经度和纬度点(比方说 50 英里)内的所有位置。

我填充了一些帖子,在帖子表中我有两列,用于在创建帖子时存储经度和纬度。该表的外观如下:

My SQL Server 2012 帖子表

我浏览了许多如何尝试实现这一点的示例,但似乎它们不起作用。通过研究我知道 ASP.NET Core 不支持DbGeography,其他文章也已经过时了。

找到这篇文章,但它使用了DbGeography,所以不起作用。

在 GitHub 上找到了这个:我只是不知道这是否可行。

仅供参考,这就是我的 Post 模型的外观:

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }

    public double Lat { get; set; }
    public double Lng { get; set; }

    public DateTime Created { get; set; }
    public Category Category { get; set; }
    public int CategoryId { get; set; }

    // Other navigation properties...
}
Run Code Online (Sandbox Code Playgroud)

这就是我现在执行查询以在前端的 Google 地图上显示点的方式:

public class HomeController : Controller
{
    private readonly ApplicationDbContext _context;

    public HomeController(ApplicationDbContext context)
    {
        _context = context;
    }


    [HttpGet]
    public JsonResult GetGalleryLocations()
    {

        var data = _context.Posts
            .Include(c => c.Category)            
            .ToList();

        return Json(data);
    }       
}
Run Code Online (Sandbox Code Playgroud)

有谁对如何实现这样的查询有任何见解?

Net*_*age 5

如果您从数据库中提取适合所需距离圆周围的正方形的数据,然后在客户端微调到仅圆中的帖子,怎么样?

给定您的初始数据

var myLat = 25.05;
var myLon = -80.3;
var radiusInMile = 50;
Run Code Online (Sandbox Code Playgroud)

您可以计算包含该圆的正方形的边界

var minMilePerLat = 68.703;
var milePerLon = Math.Cos(myLat) * 69.172;
var minLat = myLat - radiusInMile / minMilePerLat;
var maxLat = myLat + radiusInMile / minMilePerLat;
var minLon = myLon - radiusInMile / milePerLon;
var maxLon = myLon + radiusInMile / milePerLon;
Run Code Online (Sandbox Code Playgroud)

然后,您可以在数据库中查询正方形内的帖子,将它们带到客户端并仅保留圆圈内的帖子

var data = _context.Posts
                   .Where(p => (minLat <= p.Lat && p.Lat <= maxLat) && (minLon <= p.Lng && p.Lng <= maxLon))
                   .AsEnumerable()
                   .Select(p => new { p, Dist = distanceInMiles(myLon, myLat, p.Lng, p.Lat) })
                   .Where(p => p.Dist <= radiusInMile);
Run Code Online (Sandbox Code Playgroud)

其中distanceInMiles函数定义为

public double ToRadians(double degrees) => degrees * Math.PI / 180.0;
public double distanceInMiles(double lon1d, double lat1d, double lon2d, double lat2d) {
    var lon1 = ToRadians(lon1d);
    var lat1 = ToRadians(lat1d);
    var lon2 = ToRadians(lon2d);
    var lat2 = ToRadians(lat2d);

    var deltaLon = lon2 - lon1;
    var c = Math.Acos(Math.Sin(lat1) * Math.Sin(lat2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(deltaLon));
    var earthRadius = 3958.76;
    var distInMiles = earthRadius * c;

    return distInMiles;
}
Run Code Online (Sandbox Code Playgroud)

我使用余弦球面定律来计算距离,我认为这足以解决这个问题。如果您需要更高的准确性,您可以将公式升级为更复杂的公式,例如半正矢或文森蒂。