3

I am currently working on an application that will retrieve other users' locations based on distance.

I have a database that store all the user location information in latitude and longitude. Since the calculation of distance between these two pairs of latitude and longitude is quite complicated, I need a function to handle it.

from a in db.Location.Where(a => (calDistance(lat, longi, Double.Parse(a.latitude), Double.Parse(a.longitude)))<Math.Abs(distance)  )) {...}

However, I got the following error: LINQ to Entities does not recognize the method and this method cannot be translated into a store expression.

I don't know how to translated it into a store expression and also, the calculation also need the math library.

Is there any method that i can do to let the LINQ expression call my own function?

Maybe there are other ways to achieve my goal, can anyone help?

Steve Danner
  • 21,818
  • 7
  • 41
  • 51
Chleung49
  • 41
  • 7

3 Answers3

1

LinqToEntities won't allow you to call a function, it doesn't even allow ToString()

this is not a Linq thing its a LinqToEntities restriction

you could put your code in to the database as a Stored Proc or Function and call it using ExecuteStoreQuery

see here Does Entity Framework Code First support stored procedures?

Community
  • 1
  • 1
Anthony Johnston
  • 9,405
  • 4
  • 46
  • 57
0

The problem you see is that the LINQ to SQL engine is trying to inject T-SQL from your user-defined function and it cannot. One (albeit nasty) option is to retrieve all of your locations and then calculate from that result set.

var locations = db.Location.ToList();
locations = locations.Where(a => (calDistance(lat, longi, Double.Parse(a.latitude), Double.Parse(a.longitude))).ToList();
Steve Danner
  • 21,818
  • 7
  • 41
  • 51
0

I don't really know LINQ, but assuming that you can only send simple constraints in the query, I would construct a method that basically does the inverse of calDistance - take a coordinate and a distance and convert it into a bounding box with a minimum longitude, maximum longitude, minimum latitude, and maximum latitude.

You should be able to construct a simple query that will serve your purposes with those constraints.

something like (using Java here):

public double[] getCoordinateBounds(double distance, double longitude, double latitude) {
    double[] bounds = new double[4];
    bounds[0] = longitude - distanceToLongitudePoints * (distance);
    bounds[1] = longitude + distanceToLongitudePoints * (distance);
    bounds[2] = latitude - distanceToLatitudePoints * (distance);
    bounds[3] = latitude + distanceToLatitudePoints * (distance);
    return bounds;
}

Then you could construct a query.

double[] bounds = getCoordinateBounds(distance, longi, lat);
var nearbyUserLocations = from a in db.Location 
                         where longitude > bounds[0] and longitude < bounds[1]
                            and latitude > bounds[2] and latitude < bounds[3]

This would give you a box of points rather than a radius of points, but it would be few enough points that you could then process them and throw out the ones outside your radius. Or you might decide that a box is good enough for your purposes.

Brian Cooley
  • 11,622
  • 4
  • 40
  • 39