.NET Core 6 EF Core中SQL Server Geography类型支持问题咨询
我有一个.NET Core 6应用程序和SQL Server数据库,其中某表包含类型为Geography的列。我的目标是用LINQ查询获取距离指定点小于40000米的行列表。现有可正常执行的T-SQL语句如下:
-- SPATIAL WITHIN DISTANCE DECLARE @Origin GEOGRAPHY, -- 距离单位为米 @Distance INTEGER = 40000; -- 中心点 SET @Origin = GEOGRAPHY::STGeomFromText('POINT(-93.5663 44.9033)', 4326); -- 返回40公里范围内的所有行 SELECT * FROM dbo.GeographyAreas WHERE @Origin.STDistance(Geography) <= @Distance;
我更倾向于在应用数据层用LINQ语法实现,而非存储过程,但遇到了SQL Server Geography列类型与空间库的匹配问题:
NetTopologySuite支持Geometry类型,但似乎不支持Geography;Microsoft.Spatial的Geography类型无法映射到SQL Server的Geography类型;Microsoft.SqlServer.Types适用于传统.NET,而非.NET Core。
我期望实现类似如下的代码:
public class GeographyAreas { public <SomeGeographyType> Geography { get; set; } } var origin = <SomeGeographyType>(-93.123, 44.456); var dist = 40000; List<GeographyAreas> results = _context.GeographyAreas.Where(x => x.Geography.Distance(origin) < dist).ToList();
但执行时出现错误:
The Geography property of GeographicAreas.Geography could not be mapped because the database provider does not support this type
想咨询是否可以通过Entity Framework Core实现该需求,还是应该采用存储过程执行上述T-SQL代码?
完全可以通过EF Core实现你的需求,无需依赖存储过程,具体步骤如下:
1. 安装必要的NuGet包
在.NET Core 6中,EF Core对SQL Server地理类型的支持需要依赖以下两个包:
Microsoft.EntityFrameworkCore.SqlServer(EF Core SQL Server核心提供者)Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite(为SQL Server添加NetTopologySuite的空间类型支持)
2. 配置DbContext
在你的DbContext的OnConfiguring方法中,启用NetTopologySuite支持,让EF Core能正确映射SQL Server的Geography列:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( "你的数据库连接字符串", x => x.UseNetTopologySuite()); }
3. 实体类定义
使用NetTopologySuite.Geometries.Point类型映射SQL Server的Geography列,注意指定SRID为4326(WGS84坐标系,对应SQL Server地理类型的默认坐标系):
using NetTopologySuite.Geometries; public class GeographyAreas { // 其他业务属性... public Point Geography { get; set; } }
4. 编写LINQ查询
直接使用Distance方法即可,EF Core会自动将其转换为SQL Server的STDistance函数,实现球面距离计算(单位为米):
using NetTopologySuite.Geometries; // 创建对应SRID的几何工厂 var geometryFactory = new GeometryFactory(new PrecisionModel(), 4326); // 注意构造Point时参数顺序为(经度, 纬度),对应WKT的POINT格式 var origin = geometryFactory.CreatePoint(new Coordinate(-93.123, 44.456)); var dist = 40000; List<GeographyAreas> results = _context.GeographyAreas .Where(x => x.Geography.Distance(origin) <= dist) .ToList();
关键说明
- 虽然NetTopologySuite的
Point属于Geometry类型,但通过UseNetTopologySuite()配置后,它会正确映射到SQL Server的Geography列,并且支持地理空间的球面计算逻辑。 - 确保数据库中
Geography列的SRID为4326,若使用其他坐标系,需同步调整代码中GeometryFactory的SRID参数。
备选方案(若上述方法受限)
如果因特殊原因无法使用NetTopologySuite,也可以通过EF Core原生SQL查询实现,无需创建存储过程:
var originWkt = "POINT(-93.123 44.456)"; var dist = 40000; var results = _context.GeographyAreas .FromSqlRaw(@" SELECT * FROM dbo.GeographyAreas WHERE GEOGRAPHY::STGeomFromText({0}, 4326).STDistance(Geography) <= {1}", originWkt, dist) .ToList();
内容的提问来源于stack exchange,提问作者shage_in_excelsior

