多年来,我一直Microsoft.SqlServer.Types.dll
在 WPF 和 ASP.NET 应用程序中使用SqlGeometry
类型和空间查询(自 v.10 起),这里是我发现成功SqlServerSpatialXXX.dll
加载Microsoft.SqlServer.Types.dll
.
SqlGeometry
和SqlGeography
类型可以通过引用Microsoft.SqlServer.Types.dll
.
Microsoft.SqlServer.Types.dll
是一个托管库,有一些非托管库作为先决条件,它们就像SqlServerSpatialXXX.dll和msvcrXXX.dll
- 自 Sql Server 2008 以来,可以使用不同的版本
Microsoft.SqlServer.Types.dll
,但是,从 2012 年开始,我看不到任何功能变化。
考虑 64bit/32bit 问题
- 对于 64 位机器,如果您安装 CLR Types for Sql Server,您可以在Windows/System32中找到这些必备文件的 64 位版本,也可以在Windows/SysWOW64文件夹中找到 32 位版本的必备文件
- 如果机器上没有安装 CLR 类型,您应该根据您的项目(32 位或 64 位)手动加载这些先决条件的正确版本(32 位/64 位),否则您会出现类似错误
加载 SqlServerSpatialXXX.dll 时出错
您可以在 C# 中使用运行时检查 32 位/64 位问题Environment.Is64BitProcess
。这是一个示例代码:
[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 客户端默认加载版本 10.0.0.0的Microsoft.SqlServer.Types.dll
。在这种情况下,几年前我尝试使用 WKB(方法 1 和 2)和 WKT 作为在SqlGeometry
不同版本的类型之间进行转换的媒介Microsoft.SqlServer.Types.dll
,发现 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())
{
//approach 1: using WKB. 4100-4200 ms for hundred thousands of records
//geometries.Add(SqlGeometry.STGeomFromWKB(new System.Data.SqlTypes.SqlBytes((byte[])reader[0]), srid).MakeValid());
//approach 2: using WKB. 3220 ms for hundred thousands of records
//geometries.Add(SqlGeometry.Deserialize(reader.GetSqlBytes(0)));
//approach 3: exception occur if you forget proper assembly redirection. 2565 ms for hundred thousands of records
geometries.Add((SqlGeometry)reader[0]);
}
connection.Close();
return geometries;
}