[記錄]Microsoft.SqlServer.Types 無法載入 DLL 'SqlServerSpatial130.dll'

  • 991
  • 0
  • 2019-10-10

因為專案會用到 SqlGeometry,所以引用 Microsoft.SqlServer.Types 但卻出現錯誤訊息 

無法載入 DLL 'SqlServerSpatial130.dll': 找不到指定的模組。 (發生例外狀況於 HRESULT: 0x8007007E) 

其實在 11.0.2 之後的 NuGet Package 皆已附上解法:

如果 ASP.NET 就在 Application_Start 方法加一行:

SqlServerTypes.Utilities.LoadNativeAssemblies(Server.MapPath("~/bin"));

桌面應用則是加一行:

SqlServerTypes.Utilities.LoadNativeAssemblies(AppDomain.CurrentDomain.BaseDirectory);

經過 NuGet 的配置,程式會在編譯時複製一份二進制檔(SqlServerSpatialxxx.dll)到 bin 資料夾,而 LoadNativeAssemblies 則在判斷系統為 x86、x64 後,動態載入對應的二進制檔。

 

SqlGeometry 是一個 SQL CLR 擴充型別,可以記載空間資訊並有方便的空間運算方法,從 SQL 2008 開始變成官方釋出不再需要額外安裝。

關於 SqlGeometry 的資料撈取,透過 NuGet 引用 Microsoft.SqlServer.Types,有了對應的型別後,可直接用 ADO.NET 從資料庫 Select 出來:

void Main()
{
	var conn = new SqlConnection(_connStr);
	var dt = new DataTable("table");
	var cmd = conn.CreateCommand();
	cmd.CommandText = " DECLARE @g geometry = 'LINESTRING(3 4, 8 11)' SELECT @g.STBuffer(2)";

	var ad = new SqlDataAdapter(cmd);
	ad.Fill(dt);

	//撈到 SqlGeometry 囉
	SqlGeometry geo = dt.Rows[0][0] as SqlGeometry;

	//無法載入 DLL 'SqlServerSpatial130.dll'
	//geo.STBuffer(5);

	Console.WriteLine(geo.ToString());
}

大致上不要在應用程式用到空間運算功能,都是不會出現本篇所提的錯誤信息,甚至在資料庫端完成空間運算也是沒有問題的,例如上面的 @g.STBuffer(2) 就是。

如果開發環境是 VS2017 那麼使用 Microsoft.SqlServer.Types 14.0.314.76 ,在開發時是完全沒有任何錯誤信息,因為這個版本所對應的是 SQL 2017,剛好是 VS2017 所用到 LocalDB 版本。

所以要是有人開發環境從 2008 開始每套都安裝過一輪,類似的錯誤訊息可能要到程式上線時才會被發現。

結論

錯誤原因是應用程式執行環境沒有安裝 SQL 2016(130),雖然可以透過安裝相關元件來解決,但卻不是最佳解,因為和環境耦合,甚至也存在無法安裝的情境,例如 Azure Application。目前較好的方法是動態載入。

以上是應用程式面的解法,而如果是類別庫開發,參考 Dapper 的作法,Dapper 作為一個 ORM 類別庫它也提供了 SqlGeometry 的對應功能,但它並沒有去作 SqlServerSpatialxxx.dll 的載入,而是留給使用者去搞定,對應的是使用者對 SqlGeometry 的版本及載入方式有更好的掌控程度。