将SQL的地理数据类型转换为DBGeography?

18
也许我漏掉了什么。我有一个SQL Server列,数据类型为“Geography”。
我想在我的C#代码中使用DbGeography类型。有没有将SQL的geography转换为dbgeography的方法或者进行强制转换?
6个回答

29
抱歉回复晚了 - 在寻找其他东西时看到了这个。
只需按照以下步骤操作:
SqlGeography theGeography;
int srid = 4326; // or alternative

DbGeography newGeography = DbGeography.FromText(theGeography.ToString(), srid);

要将它翻转:

DbGeography theGeography;
SqlGeography newGeography = SqlGeography.Parse(theGeography.AsText()).MakeValid();

希望能对您有所帮助!


我正在另一个项目上,这个问题再次出现了,所以谢谢你,这正是我在寻找的。 - Eric
@jm2 如果你已经引用了 Microsoft.SqlServer.Types 库,它应该对你可用。 - Jon Bellamy
@JonBellamy 我有Assembly v10.0.0.0和runtime v2.0.50727。SqlGeometry和SqlGeography类型都可用,SqlGeometry有MakeValid方法但SqlGeography没有。可能是引用了错误的版本?这可能更适合另一个问题。 - joelmdev
如果您不想硬编码SRID,可以使用 DBGeography.FromText(theGeography.ToString(), theGeography.STSrid.Value) - Anthony Mills
2
为了后代,"MakeValid"问题是SQL Server版本的问题。据我所知,直到SQL Server 2012版本之前,MakeValid不是SqlGeography类型的函数。因此,如果安装了早期版本的SQL Server,则即使在引用Microsoft.SqlServer.Types时,在.NET应用程序中也无法使用MakeValid函数。我不知道有没有办法更新程序集版本而不更新SqlServer版本。也许你可以从某个地方获取dll并将其添加到GAC中,但我想这可能会导致副作用。 - joelmdev
显示剩余4条评论

10

当性能至关重要时,应使用广为人知的二进制而不是广为人知的文本:

var newGeography = DbGeography.FromBinary(theGeography.STAsBinary().Value);

如果SRID很重要,那么可以使用超载函数。在我的一千个相当复杂的多边形的简单测试中,基于二进制的方法比基于文本的方法快4倍:

* Binary-based conversion
Run 1: 1948
Run 2: 1944
Run 3: 1959
Run 4: 1979
Run 5: 1988
Average: 1963.6

* Text-based conversion
Run 1: 8527
Run 2: 8553
Run 3: 8596
Run 4: 8535
Run 5: 8496
Average: 8541.4

1
对于反向操作:SqlGeography.STGeomFromWKB(new SqlBytes(value.AsBinary()), value.CoordinateSystemId) - Marc Gravell

1

根据我在ILSpy中读取EntityFramework.SqlServer.dll的内容,我认为从SqlGeography转换为DbGeography的最快方法是:

var dbGeo = System.Data.Entity.SqlServer.SqlSpatialServices.Default.GeographyFromProviderValue(sqlGeo);

这种方法的优点在于不需要进行二进制转换和解析。它直接返回一个以SqlGeography作为内部提供程序值的DbGeography。

1

如果您没有运行EF6,提供的解决方案似乎是可以的。 对于早期版本来说,这没问题,但是对于EF6,我们不应该引用这个程序集。 它会让EF有些疯狂。


你能更具体一些吗?到底发生了什么,正确的解决方案是什么? - grahamesd
1
对于其他人来说,我仍然使用我的EF6提供的解决方案,问题。 - Jon Bellamy

1

您必须按照上述提到的方式添加对程序集的引用。 以下文章可能会对您有所帮助链接1,链接2


0
我找到了一个可行的解决方案:
int coordSys = DbGeography.DefaultCoordinateSystemId; // 4326; 
SqlGeography g = SqlGeography.Point(lat, lon, coordSys);
return DbSpatialServices.Default.GeographyFromProviderValue(g);

不要进行序列化/转换为字符串(WKT)或二进制(WKB),这会影响性能。

在EF 6.1.3、SqlServer 2016 SP1和Microsoft.SqlServer.Types.14.0.314.76上已经测试通过。


我要补充一点,如果你使用的是大于v10(SQL 2008)的SqlGeography,则此方法将会抛出一个错误,这意味着如果你需要任何SQL 2012及以上版本的功能,那么你就完了。不过性能还是很好的。 - Jon Bellamy
我假设也没有反向方法吗? - Jon Bellamy
应该有一个反转方法,现在还不能确定。 - Sergei Zinovyev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接