天天看點

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的類庫。

EntityFramework Core連接配接國産達夢資料庫

并且在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管理器安裝,失敗!

EntityFramework Core連接配接國産達夢資料庫

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指令,資料表成功被建立!繼續測試了其他功能,查詢沒有問題,插入、更新、删除都還存在問題,原因正在查找中。

2-25補充

繼續測試,更換多個版本的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,尚未完成,不能使用。

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

2-28再次補充

發給達夢官方的郵件今天有回複了,說是支援EFCore3.1驅動正在開發中,就讓我們翹首以待吧!

參考資料:

  • DM6中登入-使用者-模式的關系
  • FreeSql