EntityFramework Core連接國產達夢數據庫

近期意外發現了國產達夢數據庫對.NET Core環境下EFCore的支持,把測試過程分享如下。


1.測試環境

  • .Net Core 2.1
  • EntityFramework Core 2.2.4
  • DM v8(達夢)
  • Window 10 x64

2.踩坑記錄

近些年數據庫等基礎設施國產化的呼聲越來越高,達夢也算國產數據庫中知名度較高的了,不過開發生態環境還不夠完善,使用過程中也是各種坑。

2.1達夢數據庫的.NET驅動

達夢數據庫提供了dotNet、jdbc、odbc等多種驅動方式,在安裝目錄的drivers目錄下都可以找到。市面上找了很久都沒有發現.NET Core環境下連接達夢數據庫的方案。2019年國內有大牛發佈了開源項目FreeSql能夠支持達夢數據庫,但底層採用的依然是odbc驅動。

在瀏覽達夢數據庫安裝目錄時意外發現了EFCore.Dm的類庫。
在這裏插入圖片描述
並且在drivers/dotNet目錄下的readme文件中也發現這樣一段文字。

達夢.Net驅動分爲DmProvider、EFDmProvider、EFCore.Dm、DmDialect和DmConnect。
DmProvider可以在.NET框架和NETCore框架下使用,NETCore框架下需要用戶安裝System.Text.Encoding.CodePages包或者直接以NUGET包的形式安裝DmProvider,可以自動依賴的System.Text.Encoding.CodePages包
其中EFDmProvider是支持Entity Framework框架的驅動,它與數據庫交互的部分由DmProvider完成,所以如果程序中需要使用EFDmProvider,需要同時引用DmProvider
DmConnect是達夢提供給VS的DDEX驅動,它也引用了DmProvider。
EFCore.Dm已支持EFCore2.1版本
DmDialect方言包有for Nhibernate3、for Nhibernate4、for Nhibernate5分別對應NET3.5、NET4、NET4.6.1;用戶可根據開發環境選擇對應的方言包版本;
Nhibernate中App.config配置要求:
1、驅動名稱
NHibernate.Driver.DmDriver, DmDialect, Version=1.0.0.0, Culture=neutral, PublicKeyToken=072d25982b139bf8
2、方言包名稱
NHibernate.Dialect.DmDialect, DmDialect, Version=1.0.0.0, Culture=neutral, PublicKeyToken=072d25982b139bf8
文件結構說明:
DmProvider文件夾中是完整的DmProvider驅動文件。使用DmProvider的DmBulkCopy對象,需要引用dmfldr_dll.dll以及此dll依賴的其他庫。
EFDmProvider文件夾中是老版本的EFDmProvider,已不再更新版本。
EFDmProvider6.1.3-net40文件夾中是基於EntityFramework6.1.3及.Net4.0的EFDmProvider 2.0版本。
EFDmProvider6.1.3-net45文件夾中是基於EntityFramework6.1.3及.Net4.5的EFDmProvider 2.0版本。
DmConnect文件夾中是DmConnect驅動及所需文件。
DmDialect文件夾是不同版本NHibernate的方言包
gacutil.exe是全局程序集緩存工具,使用它可以將.Net驅動加載到程序集中。

既然你說你已支持,那就試試。

2.2安裝Microsoft.EntityFrameworkCore.Dm

將Microsoft.EntityFrameworkCore.Dm添加到本地的程序包源,使用NuGet管理器安裝,失敗!

在這裏插入圖片描述
Internal.AspNetCore.Sdk是什麼?打開nupkg文件,猜測就是AspNetCore.SDK的非正式環境,這估計也就解釋了爲什麼這個程序包會藏在這裏而在NuGet官方市場上找不到,看來是未完成的測試版了。此處是第一坑。

2.3直接引用類庫

無法使用NuGet管理器安裝,就根據Microsoft.EntityFrameworkCore.Dm的依賴關係直接引用相關類庫。直接在項目中引用“drivers\dotNet\DmProvider\netstandard2.0”目錄下的DmProvider.dll和“drivers\dotNet\EFCore.Dm\netstandard2.0”目錄下的Microsoft.EntityFrameworkCore.Dm.dll。編譯成功。修改數據庫連接字符串,啓動項目,數據庫連接成功。

使用EFCore的CodeFirst模式創建實體類並建立與數據庫表的映射關係,執行"update-databse"命令,總是提示“不存在表XXXX”。經過查閱達夢數據庫文檔才發現,問題可能出在用於登錄數據庫的用戶身上。

在達夢數據庫中有模式、登錄和用戶三個不同的概念,在官方技術論壇上有這樣一段描述:

一、登錄、用戶、模式的定義
登錄是相對於數據庫服務器而言的,它僅僅代表着連接到數據庫實例的權利,但並不代表創建登錄就能操作數據庫服務器裏面的任何數據庫(在達夢數據庫中,一個數據庫實例可以包含多個數據庫)。
用戶是相對於數據庫實例中特定數據庫來說的,數據庫中的用戶擁有對該數據庫中指定範圍內的對象的操作權利。
模式用來代表特定數據庫中的一個對象集,在概念上可將其看作是包含表、視圖、索引和權限定義的對象集合。一個模式只作用於一個數據庫,不同的數據庫可以有同名模式。
二、登錄、用戶、模式的關係
一個登錄可以對應多個不同數據庫中的用戶,單個數據庫中最多只能有一個用戶與某一登錄對應,沒有登錄與之對應的用戶是沒有意義的。一個用戶可以創建多個模式,一個模式中的對象(表、視圖等)可以被多個用戶使用。一個用戶可以訪問他所屬數據庫中的任意模式中的對象,只要授予他相應的權限。
爲了更好的理解三者之間的關係,下面打個比喻。有一間房(對應一個達夢數據庫運行實例),房裏有多個保險櫃(對應實例中的多個數據庫),每個保險櫃又有多個抽屜(對應所在數據庫中的模式),抽屜裏存放一些貴重的物品(對應數據庫中的某個模式下的表、視圖等數據實體)。
我們要進入房間需要房間的鑰匙(對應登錄名),進入房間後我們要打開保險櫃需要保險櫃的鑰匙(對應用戶名),並且進入房間並不代表我們可以打開保險櫃,我們只有是某一保險櫃的使用用戶才能打開保險櫃,以一個登錄身份進入房間後,我們可能是多個保險櫃的使用用戶,這樣我們有可能可以打開多個保險櫃(一個登錄可以對應多個不同數據庫中的用戶)。對保險櫃而言,不同的用戶身份對應保險櫃中不同的抽屜,打開保險櫃後,依據用戶身份的不同,決定用戶所能使用的抽屜,保險櫃的一個用戶可以使用多個抽屜,一個抽屜也可能被多個用戶使用(一個用戶可以創建多個模式,一個模式中的對象可以被多個用戶使用)。

簡單消化了上述文字,檢查數據庫發現用到的用戶被鎖定了,修改了用戶選項,錯誤消失。此處是第二坑。

2.4 .NET Core 2.x環境

上面的錯誤消失了,又一個新的錯誤出現了。

“Method ‘get_Info’ in type ‘Microsoft.EntityFrameworkCore.Dm.Infrastructure.Internal.DmOptionsExtension’ from assembly ‘Microsoft.EntityFrameworkCore.Dm, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60’ does not have an implementation”

大意就是某個方法沒實現,思來想去又從頭檢查了一遍,才發現是自己坑了自己。原來是我創建項目是默認選擇了.NET Core 3.1的開發環境,人家說的是支持.NET Core 2.1,錯誤原因就在這裏。將項目改成了.NET Core 2.1,重新編譯項目,執行EFCore命令,數據表成功被創建!繼續測試了其他功能,查詢沒有問題,插入、更新、刪除都還存在問題,原因正在查找中。


補充

繼續測試,更換多個版本的EntityFramework Core(僅限於2.x版本),插入、更新、刪除均報錯,詳細信息如下:

System.MissingMethodException: Method not found: 'Dm.DmTransaction Dm.DmConnection.BeginTransaction(System.Data.IsolationLevel)'.
         at Microsoft.EntityFrameworkCore.Dm.Storage.Internal.DmRelationalConnection.BeginTransactionWithNoPreconditions(IsolationLevel isolationLevel, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Dm.Storage.Internal.DmRelationalConnection.BeginTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransactionAsync(CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext _, ValueTuple`2 parameters, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Dm.Storage.Internal.DmExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IReadOnlyList`1 entriesToSave, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)

基本可以證明達夢8的.NET驅動EFCore.Dm存在BUG,尚未完成,不能使用。

還望達夢官方能早日更新,完善生態,造福廣大開發者!


參考資料:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章