0

我有一個測試數據庫和位於不同服務器上的實時數據庫。我目前的設計設法與兩個工作,但我想改善訪問。我現在沒有想法,希望得到您的意見。VB.NET實體框架訪問多個數據庫服務器與幾個DbContext類


問題

我該如何解決以下設計問題?

我創建了兩個EF6類來訪問不同的數據庫。 (突出顯示的) EF6-classes

在程序啓動時,我根據構建模式定義了一個默認連接。

​​

然後,我使用myDBType創建DBAccess對象與我的數據庫進行交互。從現在開始,它會自動連接到測試數據庫或活動數據庫。

Dim userAccess = new UserDBAccess(myDBtype) 
userAccess.GetUser() 
userAccess.Dispose() 

Dim projectAccess = new ProjectDBAccess(myDBType) 
projectAccess.DoWork() 
projectAccess.Dispose() 

我在YouTube上觀看https://www.youtube.com/watch?v=sA-Hp4aBWb4一個SW-架構的視頻,我修改我的需求後得到了這個想法。

因此,直到現在,這看起來像一個非常乾淨的方式,但我遇到了麻煩。

我的問題是,對於每個數據庫訪問,我必須複製/粘貼99%的代碼,具體取決於我想訪問的服務器。例如。

對於現場DB:下面

對於TESTDB ctxLive < @see代碼:ctxTest < @see代碼如下

我有一個基類,所有DBACCESS類派生。

Imports System.Data.Entity 
Public MustInherit Class AbstractDBAccess 
    Implements IDisposable 
#Region "Fields" 
    ' Access live db via EF 6 
    Protected ctxLive As DBLiveEntities 

    ' Access test db via EF 6 
    Protected ctxTest As DBTestEntities 

    ' Remember DB to access 
    Protected myDBType As DatabaseType 
#End Region 
#Region "Enum" 
    ''' <summary> 
    ''' Add more data bases here. 
    ''' </summary> 
    ''' <remarks>Matthias Köhler</remarks> 
    Public Enum DatabaseType 
     Live = 0 
     Test = 1 
    End Enum 
#End Region 
#Region "Constructor" 
    Public Sub New(ByVal dbType As AbstractDBAccess.DatabaseType) 

     myDBType = dbType ' 

     ' Depending on what type we get from startup we grant access to test or live DB 
     Select Case dbType 
      Case DatabaseType.Live 
       Me.ctxLive = New DBLiveEntities 

      Case DatabaseType.Test 
       Me.ctxTest = New DBTestEntities 
     End Select 
    End Sub 
#End Region 
#Region "Methods" 
    Public Function GetDBAccess() As DbContext 
     ' My Problem is i need to return two different types in this method. 
     ' After creating an instance I save which access this object was intended for with "myDBType" 
     ' Both classes derive from DbContext but if I implement it this way I can't see my tables. See screenshot below. 
     Select Case myDBType 
      Case DatabaseType.Live 
       Return Me.ctxLive 
      Case DatabaseType.Test 
       Return Me.ctxTest 
     End Select 

     Throw New Exception("No matching case for " & myDBType.ToString) 
    End Function 
#End Region 

的問題

您看到選擇情況是99%相同。想象一下複雜的代碼和15個類。我只是不喜歡那個複製粘貼。我只需要更改「ctxLive」或「ctxTest」。

想象一下,在某些年份某人不得不添加另一個數據庫。他必須瀏覽整個代碼併爲每種方法添加一個案例。

難道還有更好的辦法嗎?

Can't-see-tables

這裏這個截圖匹配碼。

Public Class UserDBAccess 
    Inherits AbstractDBAccess 
    Implements IDisposable 

    Public Sub New(ByVal dbType As AbstractDBAccess.DatabaseType) 
     MyBase.New(dbType) 
    End Sub 

    Public Sub GetUser() 
     ' Currently I have to add a lot of select cases to seperate my live DB and test DB. 
     ' They have different connection strings and are on different servers 
     Select Case Me.myDBType 
      Case DatabaseType.Live 
       Me.ctxLive.CCTUsers.Where(Function(u) u.UserName.Contains("StackOverflow")) 
      Case DatabaseType.Test 
       Me.ctxTest.CCTUsers.Where(Function(u) u.UserName.Contains("StackOverflow")) 
     End Select 

     ' I have a lot of Copy Pasting which in my opinion is ugly. 
     ' I want sth like this to save me all that select cases 
     ' The difference here is the "GetDBAccess" 
     Me.GetDBAccess.CCTUsers.Where(Function(u) u.UserName.Contains("StackOverflow")) 
    End Sub 
End Class 
+0

通常這是通過配置處理的。上下文從配置中設置的任何數據庫連接加載。使用的配置綁定到構建模式。那麼只需要一個數據庫上下文。 – dbugger

+0

我在上面。你給了我一個好主意。如果我解決了這個問題,我會回答。 –

+0

我會建議在app.config文件中使用自定義組。 – codeMonger123

回答

1

以下解決方案絕對更清潔,更易於日後維護。

將連接字符串添加到您的應用程序。配置

<connectionStrings> 
    <add name="DB_Live" connectionString="liveDB" providerName="System.Data.EntityClient" /> 
    <add name="DB_Test" connectionString="testDB" providerName="System.Data.EntityClient" /> 
</connectionStrings> 

創建DBEntityManager

Public Class DBEntityManager 
Inherits DbContext 

Public Sub New(ByVal connString As String) 
    MyBase.New(connString) 
End Sub 

Public Overridable Property MyTable() As DbSet(Of MyTable) 

End Class 

然後我加入到ConfigurationManager中的引用:

  1. 右鍵單擊您的項目(不解決方案)
  2. 添加 - >參考。 .. - > Framework
  3. 搜索「配置」並激活che對於「System.Configuration」
  4. 單擊「確定」

在啓動時,我配置取決於構建模式

#If DEBUG Then 
     connString = Configuration.ConfigurationManager.ConnectionStrings("DB_Test").ConnectionString() 
#Else 
     connString = Configuration.ConfigurationManager.ConnectionStrings("DB_Live").ConnectionString() 
#End If 

我重新分解我的基類來查找連接字符串CK盒喜歡這個。

它現在需要連接字符串並創建一個DBEntityManager對象。 DBEntityManager派生自DBContext並使用傳遞的連接字符串。

Public Class DBAccessAbstract 
    Implements IDisposable 

#Region "Field Declaration" 
    Protected ctx As DBEntityManager 
#End Region 

#Region "Constructors" 
    Public Sub New(ByVal connString As String) 
     ctx = New DBEntityManager(connString) 
    End Sub 
#End Region 

#Region "IDisposable Support" 
    Private disposedValue As Boolean ' To detect redundant calls 

    ' IDisposable 
    Protected Overridable Sub Dispose(disposing As Boolean) 
     If Not Me.disposedValue Then 
      If disposing Then 
       Me.ctx.Dispose() 
      End If 

      ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below. 
      ' TODO: set large fields to null. 
     End If 
     Me.disposedValue = True 
    End Sub 

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources. 
    'Protected Overrides Sub Finalize() 
    ' ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. 
    ' Dispose(False) 
    ' MyBase.Finalize() 
    'End Sub 

    ' This code added by Visual Basic to correctly implement the disposable pattern. 
    Public Sub Dispose() Implements IDisposable.Dispose 
     ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. 
     Dispose(True) 
     GC.SuppressFinalize(Me) 
    End Sub 
#End Region 

End Class 

對於我創建的訪問器,我想

Public Class DBAccessUserTable 
Inherits DBAccessAbstract 
Implements IDisposeable 

Public Sub New(ByVal connString as String) 
MyBase.New(connString) 
End Sub 
    Public Function Exists(ByVal userName As String) As Boolean 
    Dim user As UserTable 

     user = Me.ctx.UserTables.Where(Function(e) e.UserName.Contains("StackOverflow")).FirstOrDefault 
     If IsNothing(user) Then Return False 
     Return True 
    End Function 
End Class 

現在我可以訪問任何測試或居住DB每個表創建我的DBACCESS類的新實例會自動

Dim dbEmpl As New DBAccessUserTable(Me.connString) 
      If Not dbEmpl.Exists(userName) Then Throw New System.Exception(userName & " doesn't exist.") 
      MessageBox.Show("True!") 
      dbEmpl.Dispose() 

謝謝你給我這個主意!

+0

您可以更進一步,只需在配置文件中有一個連接字符串,可以根據所選的生成配置使用適當的值填充該連接字符串。 – dbugger

+0

我會記住這一點,謝謝。但是我需要實現一個新功能,沒有時間深入挖掘。現在它工作正常,我很高興。花了我〜2:30小時修復愚蠢的複製/粘貼錯誤。當我有更多的時間,我會嘗試更新這取決於你的意見。謝謝! –