Spatial data, also known as geospatial data, is information about a physical object that can be represented by numerical values in a geographic coordinate system. Many applications nowadays make heavy use of spatial data for analysis and to make important business decisions. Consider the examples of online taxi apps, like Uber or Ola. Their whole business model is running based on the location-based data.
A spatial database is a database that is optimized for storing and querying data that represents objects defined in a geometric space. Most spatial databases allow the representation of simple geometric objects, such as points, lines, and polygons. Microsoft introduced two spatial data types with SQL Server 2008: geometry and geography. Similarly, databases like PostgreSQL, MySQL also provide spatial data types.
With the release of Entity Framework Core 2.2, Microsoft brought support for spatial types and queries in EF Core. With the introduction of spatial types, we could do queries like whether a location falls in a certain area, or queries based on the distance between two points, etc.
EF Core supports mapping to spatial data types using the NetTopologySuite spatial library.
We will create a sample ASP.NET Core MVC application to learn how to use spatial types in EF Core. Note that we need EF Core version 2.2 and above to support spatial types. This MVC application will collect a latitude and longitude as user input and list a set of tourist attraction places in the ascending order of distance from the input location. I will be using Visual Studio Code and DotNet CLI for development.
- Create a directory SpatialSample. Open Visual Studio Code and run the command dotnet new mvc --name SpatialSample in the terminal. This shall create an ASP.NET Core MVC application for us.
- In order to use spatial data with EF Core, we need to install the appropriate supporting NetTopologySuite package from Nuget based on the SQL provider we use. Since I am using SQL Server as my database I need to add the Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite package. Run the command dotnet add package Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite --version 2.2.4 in the terminal to add the package.
- using System.ComponentModel.DataAnnotations.Schema;
- using GeoAPI.Geometries;
- namespace SpatialSample.Entities
- {
- public class TouristAttraction
- {
- public int Id { get; set; }
- public string Name { get; set; }
- [Column(TypeName = "geometry")]
- public IPoint Location { get; set; }
- }
- }
Observe the Location property in the entity. It is of type IPoint. It is a NetTopologySuite type which is used to represent a location as a point. Note that I have configured the Location properties column type as geometry. This is because, in SQL Server, spatial properties are mapped to geography type by default.
Now, let's add our DbContext class. Create a class called SpatialDbContext.cs.
- using GeoAPI.Geometries;
- using Microsoft.EntityFrameworkCore;
- using NetTopologySuite;
- using SpatialSample.Entities;
- namespace SpatialSample
- {
- public class SpatialDbContext : DbContext
- {
- public DbSet<TouristAttraction> TouristAttractions { get; set; }
- public SpatialDbContext(DbContextOptions options) : base(options) { }
- }
- }
- services.AddDbContext<SpatialDbContext>(opts =>
- {
- opts.UseSqlServer(
- "<Connection string goes here>",
- x => x.UseNetTopologySuite()
- );
- });
We need to add the migration to create our database. Run the command dotnet ef migrations add AddTouristAttractionTable. After the migrations are created, run the command dotnet ef database update to apply the migrations on the database.
We need to add some seed data for the application. We will add some tourist attraction destinations in the database. We can override the OnModelCreating method of DbContext class to add seed data.
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
- modelBuilder.Entity<TouristAttraction>()
- .HasData(
- new TouristAttraction
- {
- Id = 1,
- Name = "Taj Mahal",
- Location = geometryFactory.CreatePoint(new Coordinate(27.175015, 78.042155))
- },
- new TouristAttraction
- {
- Id = 2,
- Name = "The Golden Temple of Amritsar",
- Location = geometryFactory.CreatePoint(new Coordinate(31.619980, 74.876485))
- },
- new TouristAttraction
- {
- Id = 3,
- Name = "The Red Fort, New Delhi",
- Location = geometryFactory.CreatePoint(new Coordinate(28.656159, 77.241020))
- },
- new TouristAttraction
- {
- Id = 4,
- Name = "The Gateway of India, Mumbai",
- Location = geometryFactory.CreatePoint(new Coordinate(18.921984, 72.834654))
- },
- new TouristAttraction
- {
- Id = 5,
- Name = "Mysore Palace",
- Location = geometryFactory.CreatePoint(new Coordinate(12.305025, 76.655753))
- },
- new TouristAttraction
- {
- Id = 6,
- Name = "Qutb Minar",
- Location = geometryFactory.CreatePoint(new Coordinate(28.524475, 77.185521))
- }
- );
- }
After adding the seed data, we need to create another migration as data seeding has become part of EF migrations in .NET Core. Run the command dotnet ef migrations add AddSeedData. After the migrations are created run the command dotnet ef database update to apply the migrations on the database.
We can verify by checking the TouristAttractions table in the database.

We need to create the web part of our application next. We shall create View Model classes first. We create a View Model to bind the user input and a view model to bind the list of location information based on the user search.


Mohammad KomaeiPosted Oct 20, 2020, 4:38 PM
How can we save circular or polygonal area of a restaurant delivery border in sql server with .net core 3.1 web api? could you give us a sample for that?
Sarathlal SaseendranPosted Jun 3, 2019, 10:58 AM
Very interesting one Geo.