简体   繁体   中英

C# - LINQ - shortest distance by GPS latitude and longitude

I have database and in it I have class hotel with gps coordinates. I want to get closest places to coordinates which I choose.

I think It should look like this (I found many example codes here and like this one):

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);

The problem is that I have this error when I tried to search for something:

Only parameterless constructors and initializers are supported in LINQ to Entities

I tried to google it and I found that dividing that linq into two can help me but I am not sure how. Thanks for help.

You can use the object initializer instead of parameterized constructor:

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);

But you will likely have problems caused by the GetDistanceTo method, could you provide the implementation of that method?

I have had a reasonable about of success using this implementation of the Haversine Distance formula

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);

I post here my solution which I am using for now. But I choose GwynnBliedd answer because he solves my problem in question.

I added DbGeography type to my class and I am using it instead of saving latitude and longitude in database.

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

Then it's very easy to use 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;

For now this is working solution and it's good. For sometime I would be using this but as few users said here I'll maybe try UDF with implementing Haversine formula (like in this answer ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM