0

私はテストデータベースとライブデータベースを別々のサーバーに配置しています。私の現在のデザインは、両方で動作するように管理しますが、私はアクセスを改善したいと思います。私は今考えていて、あなたの意見が欲しいです。VB.NET Entity Frameworkは複数のDbContextクラスを持つ複数のデータベースサーバーにアクセスします


質問

どのように私は次のような設計上の問題を解決することができますか?

異なるデータベースにアクセスするために2つのEF6クラスを作成しました。 (ハイライトされたもの) EF6-classes

プログラムの開始時には、ビルドモードによってデフォルトの接続を定義します。

​​

次に、myDBTypeを使用してDBとの対話を行うDBAccessオブジェクトを作成します。これからは自動的にテストDBまたはライブDBに接続します。

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

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

私は私のニーズに変更ユーチューブhttps://www.youtube.com/watch?v=sA-Hp4aBWb4上のSW-アーキテクチャのビデオを見た後にこのアイデアを得ました。

これまでのところ、これは非常にクリーンな方法のように見えますが、問題が発生します。

私の問題は、各データベースへのアクセスのために、私がアクセスしたいサーバーに応じて自分のコードの99%をコピー/ペーストする必要があるということです。例えば。 TESTDBのために

以下ctxLive < @seeコード:ライブDBについては

以下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 

問題

あなたは、Select-ケースは同じ99%でご覧ください。複雑なコードと15のクラスでこれを想像してください。私はそのコピーの貼り付けが気に入らない。私はちょうど "ctxLive"または "ctxTest"を変更する必要があります。

誰かが何年かの間に別のDBを追加しなければならないと想像してください。彼はコード全体を調べて、それぞれの方法に事件を加えなければならない。

良い方法はありませんか?ここ

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

通常、これは設定によって処理されます。コンテキストは、構成で設定されているデータベース接続からロードされます。使用される構成はビルド・モードに関連付けられています。次に、1つのデータベース・コンテキストだけが必要です。 – 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. [追加]をクリックします - >リファレンスを。 .. - >フレームワーク
  3. "構成"を検索し、私は

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

    は私が見て、私の基本クラスを-織り込ん再ビルドモードに応じて、接続文字列を設定する起動時に「System.Configuration」

  4. クリックして「OK」

ための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 

私はアクセサを作成し、私は今、私はどちらかのテストにアクセスすることができますか

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() 

私DBACCESSクラスの新しいインスタンスを作成することによって、自動的にDBを生きる

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 

に望んでいたとして、私にアイデアをくれてありがとう!

+0

これをさらに進めて、構成ファイルに1つの接続文字列を設定するだけで、選択したビルド構成に基づいて適切な値を設定できます。 – dbugger

+0

私は心から感謝しています。しかし、私は新しい機能を実装する必要があり、深く掘り下げる時間がありません。今はうまく動作し、私は満足しています。私は〜2時30分、愚かなコピー/貼り付けエラーを修正するために私を受け取りました。もっと時間があるときは、あなたのアドバイスに応じてこれを試して更新します。ありがとう! –

関連する問題