A View Inside My Head

Jason's Random Thoughts of Interest


Entity Framework Spatial: First Look

Today, I began to look into the Entity Framework June 2011 CTP which includes first class support for Spatial data types.  The ADO.NET team created an abstraction layer, based on the OGC simple features specification, with a goal being to support spatial implementations from multiple vendors.  As you would expect, SQL Server 2008 Spatial is supported out of the box.

For some reason, I was expecting a lot of work to be done on the client-side within their abstraction data type.  I was pleasantly surprised to see EF pass the heavy lifting to the underlying data store as part of the query.

For instance, I have a table in my database called Facility with a Geography column named [Geocode].  This field contains a point (single latitude/longitude pair) identifying the location of the Facility.  Even though this would normally be represented in client-side code as a SqlGeography type, EF wraps it in the new DbGeography type (i.e., the abstraction data type for ellipsoidal data).

My first query was a LINQ expression to return a list of all facilities that are within 500 miles of a given location:

var q = from f in context.Facilities
let p = DbGeography.Parse("POINT(-83 45)")
where f.Geocode.Distance(p) < 500 * 1609.344
select new { f.FacilityID, wkt=f.Geocode.AsText() };

A couple things about this query:

  1. The default SRID of 4326 is used.  This spatial reference system uses meters for distance, so my predicate needs to convert the 500 miles into meters.  Like the SqlGeography.Parse() method, DbGeography.Parse() will default to 4326.
  2. The return type is an anonymous type.  I wanted to see how the DbGeography type's .AsText() method was executed (i.e., would it be expressed in the resulting query, or would it be handled client side, etc).

When executed, the LINQ expression above generates the following TSQL:

SELECT [Extent1].[FacilityID] AS [FacilityID],
 [Extent1].[Geocode].STAsText() AS [C1]
FROM [dbo].[Facility] AS [Extent1]
WHERE ([Extent1].[Geocode].STDistance(geography::Parse(N'POINT(-83 45)'))) < cast(804672 as float(53))

As you can see, the DbGeography.AsText() was translated into the STAsText() method in the query.  And, as you might expect, the predicate's DbGeography.Distance() was properly translated into STDistance() in the TSQL WHERE clause.

The other thing that I was worried about was not having access to the actual SqlGeography type returned from the database.  I was surprised to see that EF's DbGeography has a property called ProviderValue that returns the native type that the provider supports!