1

I am using the DbGeography type in Entity Framework 6.1 with SQL Server 2014, I need to find the nearest location for possibly 100,000 entities, it is slow when doing it one by one like below, is it possible to use a similar method as I have below but do them all at once?

C#:

public List<GeocodableEntity> LinkToRoadNodes(List<GeocodableEntity> entities)
{
    foreach (var entity in entities)
    {
        var nearestLocation = GetNearestLocation(entity.Latitude, entity.Longitude, DEFAULT_ROAD_NODE_LINK_RADIUS);
        // update entity with values from nearestLocation
    }

    return entities;
}

private GeoLocation GetNearestLocation(float latitude, float longitude, double searchRadius)
{
    var sourcePoint = Helper.CreateDbGeographyPoint(latitude, longitude);
    return Locations.Where(x => x.Point.Distance(sourcePoint) < searchRadius)
        .OrderBy(x => x.Point.Distance(sourcePoint))
        .FirstOrDefault();
}

Reason I say this is because prior to this, I was doing a similar thing using a stored procedure.

Similar in SQL:

ALTER PROCEDURE [dbo].[GetNearestLocationNodesByCoordinates]
    @CoordinateList dbo.CoordinateListWithRefId READONLY
AS
BEGIN
    WITH InputCTE AS
    (
        SELECT RefID, geography::Point(Latitude, Longitude, 4326) AS Point
        FROM @CoordinateList
    )
    SELECT x.RefID, x.NodeId, x.Latitude, x.Longitude, x.LocationTypeId
    FROM (SELECT I.RefID as 'RefID',
                 L.NodeId,               
                 L.Point.Lat as 'Latitude',
                 L.Point.Long as 'Longitude',
                 L.LocationTypeId,
                 ROW_NUMBER() OVER (PARTITION BY I.RefID ORDER BY L.Point.STDistance(I.Point)) AS Ranking
          FROM InputCTE AS I
          JOIN Location AS L
          ON L.Point.STDistance(I.Point) <= 5000) AS x WHERE Ranking = 1
END

Where @CoordinateList is :

CREATE TYPE [dbo].[CoordinateListWithRefId] AS TABLE(
    [RefID] [int] NOT NULL,
    [Latitude] [float] NOT NULL,
    [Longitude] [float] NOT NULL
)

I would like to do the same thing if possible in C# code without touching stored procedures or typing a SQL query literal.

Parallel Foreach :

An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code Additional information: The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.

Community
  • 1
  • 1
sprocket12
  • 5,368
  • 18
  • 64
  • 133
  • Using a parallel foreach might help you there, as I doubt the order in which it gets the nearest neighbor matters. – Brad D Nov 11 '15 at 14:19
  • @BradD unfortunately seems DbContext's are not so thread safe. – sprocket12 Nov 11 '15 at 14:44
  • The context can't be shared on the outside. You will want to create a context to get the list of unique places, and create, call and dispose of connections within the parallel foreach – Brad D Nov 11 '15 at 20:26

0 Answers0