I am trying to migrate a webform from ASP.NET MVC to ASP.NET Core MVC. Currently I am trying to find a way to replace:
using System.Data.Entity.Spatial;
With Entity Framework Core 2.2 you can use NetTopologySuite spatial library.
You can then do a query like:
var nearestCity = db.Cities
.OrderBy(c => c.Location.Distance(currentLocation))
.FirstOrDefault();
A complete exemple is available here : https://www.markopapic.com/finding-nearby-users-using-ef-core-spatial-data/
Edit
This feature is new in EF Core 2.2
Spatial Data now added to EF Core 2.2 (see documentation)
Before EF Core 2.2 versions use this:
Now you can use Microsoft.Spatial
for geography
and geometry
spatial operations.
ofc , EntityframeworkCore
does not support spatial, so you can not create a field with geography data type in codefirst, I suggest you to do this with pure SQL commends until EntityframeworkCore
supports spatial in Q2 2017 (See this). If you don't know how I will tell you.
First of all you need to add a field with geography data type, so you need to run this commend in one of migrations up classes :
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("ALTER TABLE [dbo].[Cities] ADD [Location] geography");
}
if you are using UnitOfWork you can update Location field after you inserted a record like this :
try
{
City city = new City
{
Title = creator.Title
};
_cities.Add(city);
_uow.ExecuteSqlCommand("UPDATE Cities SET Location = geography::STPointFromText('POINT(' + CAST({0} AS VARCHAR(20)) + ' ' + CAST({1} AS VARCHAR(20)) + ')', 4326) WHERE(ID = {2})", city.Longitude, city.Latitude, city.ID);
return RedirectToAction("Index");
}
catch
{
return View(creator);
}
And now if you want to find nearby cities, you can use this commend :
var cities = _uow.Set<City>()
.FromSql(@"DECLARE @g geography = geography::STPointFromText('POINT(' + CAST({0} AS VARCHAR(20)) + ' ' + CAST({1} AS VARCHAR(20)) + ')', 4326);
Select ID, Address, CreationDate, CreationDateInPersian, CreationDateStandard, CreatorRealName, CreatorUserID, ExLanguageID, IsActive, IsDeleted, Latitude, Longitude, ModifierRealName, ModifierUserID, ModifyDate, ModifyDateInPersian, ModifyDateStandard, PhoneNumbers, Summary, TimeStamp, Title, Image from Cities
ORDER BY Location.STDistance(@g) DESC;",
35.738083, 51.591263)
.Select(x => new AllRecordsViewModel
{
ID = x.ID,
Title = x.Title
})
.ToList();
return View(cities);
// result for nearest cities :
1.Tehran
2.Ankara
3.Paris
4.Washington DC
Remember! you should select all of records except that field with geography data type!
It is purely because Entity Framework 7 doesn't support Spatial stuff. Yet. You can follow the github issue related to it here. https://github.com/aspnet/EntityFramework/issues/1100
Spatial data isn't supported yet by Entity Framework Core.
Spatial is not planned for 2.0 and we haven’t finished planning for the version after. It might be a good idea to post more details about what you would like to have in spatial support at https://github.com/aspnet/EntityFramework/issues/1100, e.g. do you use specific spatial functions or do you need rich spatial types with all kinds of spatial functionality, would you use this only with a specific database or do you need to write the same code against multiple databases? Etc.
(Source: MSDN .NET Blog)
I have made a temporary workaround to include Geography column and use it in EF Core 1.0.0 and above. It's not perfect, but it will do for now. (Similar to Hatef’s answer apparently, wow great minds think alike I guess.)
See the accepted answer on: Entity Framework Core: Type Udt is not supported on this platform. (Spatial Data - Geography)
EDIT:
Here are the official docs for NetTopologySuite with EF Core (Thanks to ono2012):
Spatial Data - EF Core
Original post:
Update 2018-12-10
Later versions of Entityframework Core now supports spatial data using the NetTopologySuite (see documentation). I think it's supported since 2.1 but I'd recommend 2.2+ due to a bug in 2.1 where coordinates are inverted when saved to database.
Your project needs to target .NET Core 2.1+ (preferably 2.2+).
I managed to get it to work with SQL Server 2016 by adding the following nuget packages:
Microsoft.AspNetCore.All
Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
To use it in your DBContext you need to add the following options in your startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<PMSdp3_Context>(o =>
o.UseSqlServer(connString, opt => opt.UseNetTopologySuite()));
}