我多年来一直在WPF和ASP.NET应用程序中使用
Microsoft.SqlServer.Types.dll
来处理
SqlGeometry
类型和空间查询(自版本10以来),这里是我发现的最新提示,可以成功加载
SqlServerSpatialXXX.dll
作为
Microsoft.SqlServer.Types.dll
的先决条件之一。
- VS项目(例如C#)中可以通过引用
Microsoft.SqlServer.Types.dll
来使用SqlGeometry
和SqlGeography
类型。
Microsoft.SqlServer.Types.dll
是一个托管库,有一些非托管库作为先决条件,它们像SqlServerSpatialXXX.dll和msvcrXXX.dll。
- 自SQL Server 2008以来,不同版本的
Microsoft.SqlServer.Types.dll
可用,但我没有看到从2012年开始的任何功能变化。
考虑64位/32位问题
- 对于64位机器,如果您安装了Sql Server的CLR类型,则可以在Windows/System32中找到这些先决条件文件的64位版本,也可以在Windows/SysWOW64文件夹中找到这些先决条件文件的32位版本。
- 如果机器上没有安装CLR类型,则应根据您的项目(32位或64位)手动加载适当版本(32位/64位)的这些先决条件,否则您将会出现错误,例如:
Error Loading SqlServerSpatialXXX.dll
您可以使用Environment.Is64BitProcess
在C#中在运行时检查32位/64位问题。以下是示例代码:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string libname);
private static void LoadNativeAssembly(string nativeBinaryPath, string assemblyName)
{
var path = Path.Combine(nativeBinaryPath, assemblyName);
if (!File.Exists(path))
{
throw new FileNotFoundException($"{path} not found");
}
var ptr = LoadLibrary(path);
if (ptr == IntPtr.Zero)
{
throw new Exception(string.Format(
"Error loading {0} (ErrorCode: {1})",
assemblyName,
Marshal.GetLastWin32Error()));
}
}
public static void LoadNativeAssembliesv13(string rootApplicationPath)
{
var nativeBinaryPath = Environment.Is64BitProcess
? Path.Combine(rootApplicationPath, @"SqlServerTypes\x64\")
: Path.Combine(rootApplicationPath, @"SqlServerTypes\x86\");
LoadNativeAssembly(nativeBinaryPath, "msvcr120.dll");
LoadNativeAssembly(nativeBinaryPath, "SqlServerSpatial130.dll");
}
考虑不同项目类型中的二进制路径
建议在项目的执行路径中有一个名为
SqlServerTypes的文件夹,像这样:
SqlServerTypes>x64
SqlServerTypes>x32
并像这样加载非托管程序集。
Utilities.LoadNativeAssembliesv13(Environment.CurrentDirectory); //WPF
Utilities.LoadNativeAssembliesv13(HttpRuntime.BinDirectory); //ASP.NET
使用ADO.NET从Sql Server读取SqlGeometry时出现的问题
无论您使用哪个版本的
Microsoft.SqlServer.Types.dll
,如果您尝试使用ADO.NET从Sql Server
读取它们,您可能会遇到转换异常,因为SQL Client默认会加载
Microsoft.SqlServer.Types.dll
的10.0.0.0版本。在这种情况下,几年前我尝试了WKB(方法1和2)和WKT作为将不同版本的
Microsoft.SqlServer.Types.dll
之间的
SqlGeometry
类型进行转换的媒介,并发现WKB大约快10倍,但是几个月前我发现使用程序集重定向我们可以强制程序加载我们正在使用的版本,并使用简单的转换即可获得
SqlGeometry
(方法3)
private List<SqlGeometry> SelectGeometries(string connectionString)
{
SqlConnection connection = new SqlConnection(connectionString);
var command = new SqlCommand(select shapeCol from MyTable, connection);
connection.Open();
List<SqlGeometry> geometries = new List<SqlGeometry>();
SqlDataReader reader = command.ExecuteReader();
if (!reader.HasRows)
{
return new List<SqlGeometry>();
}
while (reader.Read())
{
geometries.Add((SqlGeometry)reader[0]);
}
connection.Close();
return geometries;
}