Search code examples
c#.net-coreentity-framework-corespatial-querynettopologysuite

IsWithinDistance could not be translated


I'm trying to return a list of items that are within say 50 Miles of a given location.

My table (simplified) is as follows:

  • Id
  • Longitude
  • Latitude
  • Status
  • Active

I've got an initial query:

var query = db.MyTable.Where(o=> o.Status == "New" && o.Active == true);

query = query.Where(o => new Point(o.Longitude, o.Latitude)
                  .IsWithinDistance(new Point(_currentLongitude, _currentLatitude), 50));

var result = query.ToList()

However - it doesn't seem to work and am getting an error as below - any ideas how to solve this? or if there is a better way to get the nearest items?

.Where(p => new Point(p.Longitude, p.Latitude) .IsWithinDistance(geom: __p_3,
distance: ___maxDistance_4))' could not be translated.

Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

Startup.cs:

services.AddDbContext<AppDbContext>(options =>
{
                
 options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
   x => x.UseNetTopologySuite());
});

Solution

  • To make this feature work, you will need to have those coordinates stored as a Point in a SQL geography field. You can easily add this to your existing model as a computed column on a new property.

    // on your entity
    public Point Coordinates { get; }
    
    // in your db context's OnModelCreating
      modelBuilder.Entity<YourEntity>()
        .Property(x => x.Coordinates)
        .IsRequired()
        .HasComputedColumnSql("geography::Point(Latitude, Longitude, 4326)");
    

    Note, SRID 4326 is the commonly used lat/lon coordinate system supported by SQL Server. More on that here.

    Build your model and deploy to your database.

    Now that you have a spatial field and property, you can query like this:

    var point = new Point(_currentLongitude, _currentLatitude) { SRID = 4326 };
    var distanceInMeters = 50 * 1609.344;  // 50 miles to meters conversion
    var results = db.YourEntity
                    .Where(x => x.Coordinates.IsWithinDistance(point, distanceInMeters))
                    .ToList();
    

    SRID 4326 uses meters for distance, so be sure to convert as shown above if you are using miles.

    Also, if you have a lot of data you will also want to add a spatial index on that column, but EF Core doesn't support that directly yet so you'll have to do that directly in SQL.