【问题标题】:C# - LINQ - shortest distance by GPS latitude and longitudeC# - LINQ - GPS 纬度和经度的最短距离
【发布时间】:2013-01-18 16:00:42
【问题描述】:

我有数据库,其中有带 GPS 坐标的一流酒店。我想找到离我选择的坐标最近的地方。

我认为它应该是这样的(我在这里找到了很多示例代码并喜欢这个):

var coord = new GeoCoordinate(latitude, longitude);
var nearest = (from h in db.hotels
               let geo = new GeoCoordinate(h.gps.lat, h.gps.lng)
               orderby geo.GetDistanceTo(coord)
               select h).Take(10);

问题是当我尝试搜索某些内容时出现此错误:

LINQ 仅支持无参数构造函数和初始化程序 给实体

我试图用谷歌搜索它,我发现将 linq 分成两部分可以帮助我,但我不确定如何。感谢您的帮助。

【问题讨论】:

  • 目前正在尝试在数据库中进行算术运算。我怀疑如果没有大量工作,这是行不通的。你很可能想要一个存储过程或 UDF。

标签: c# linq entity-framework linq-to-entities gps


【解决方案1】:

你可以使用对象初始化器代替参数化构造器:

var nearest = (from h in db.hotels
           let geo = new GeoCoordinate{ Latitude = h.gps.lat, Longitude = h.gps.lng}
           orderby geo.GetDistanceTo(coord)
           select h).Take(10);

但是您可能会遇到由 GetDistanceTo 方法引起的问题,您能否提供该方法的实现?

【讨论】:

  • 是的,你是对的。你用无参数构造函数解决了我的问题,但我对那个方法有问题。我不是在暗示这一点。它是 GeoCoordinate 类提供的方法。正如我在其他地方发现的,我在 Linq 中只允许很少的算术运算,所以我必须使用它们并为此找到一些算法,对吗?
  • @Bibo 哦,不知道 GeoCoordinate 是一个框架类。 Linq to Entities 在内部构造了一个 SQL 脚本,一旦您在 IQueryable 上调用 ToList(),稍后将针对数据库执行该脚本,因此您是对的,您仅限于 SQL 数据操作语言的少数操作允许。
  • @Bibo 你可能会发现以下两个类有帮助:msdn.microsoft.com/en-us/library/…msdn.microsoft.com/en-us/library/…
  • msdn.microsoft.com/it-it/library/… GeoDistanceTo 实现Haversine公式。
  • 我们可以使用 AsEnumerable() var nearest = (from h in db.hotels.AsEnumerable() let geo = new GeoCoordinate{ Latitude = h.gps.lat, Longitude = h.gps.lng} orderby geo.GetDistanceTo(coord) select h).ToList();
【解决方案2】:

使用Haversine Distance 公式的这种实现,我已经获得了合理的成功

var startPoint = new { Latitude = 1.123, Longitude = 12.3 };

var closest = entities.Something.OrderBy(x => 12742 * SqlFunctions.Asin(SqlFunctions.SquareRoot(SqlFunctions.Sin(((SqlFunctions.Pi() / 180) * (x.Latitude - startPoint.Latitude)) / 2) * SqlFunctions.Sin(((SqlFunctions.Pi() / 180) * (x.Latitude - startPoint.Latitude)) / 2) +
                                    SqlFunctions.Cos((SqlFunctions.Pi() / 180) * startPoint.Latitude) * SqlFunctions.Cos((SqlFunctions.Pi() / 180) * (x.Latitude)) *
                                    SqlFunctions.Sin(((SqlFunctions.Pi() / 180) * (x.Longitude - startPoint.Longitude)) / 2) * SqlFunctions.Sin(((SqlFunctions.Pi() / 180) * (x.Longitude - startPoint.Longitude)) / 2)))).Take(5);

【讨论】:

    【解决方案3】:

    我在这里发布我现在正在使用的解决方案。但我选择 GwynnBlidd 的答案是因为他解决了我的问题。

    我在课堂上添加了 DbGeography 类型,我使用它而不是在数据库中保存纬度和经度。

    locationField = DbGeography.FromText(String.Format("POINT({0} {1})", orig.gps.lat.ToString().Replace(",", "."), orig.gps.lng.ToString().Replace(",", ".")));
    

    那么使用linq就很简单了:

    var coord = DbGeography.FromText(String.Format("POINT({0} {1})", latitude.ToString().Replace(",", "."), longitude.ToString().Replace(",", ".")));
                var nearest = (from h in db.hotels
                               where h.location != null
                               orderby h.location.Distance(coord)
                               select h).Take(limit);
                return nearest;
    

    目前这是可行的解决方案,而且很好。有一段时间我会使用它,但正如这里很少有用户所说的那样,我可能会尝试使用 UDF 来实现 Haversine 公式(如在 this answer 中)。

    【讨论】:

    猜你喜欢
    • 2017-09-05
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    相关资源
    最近更新 更多