VB.NET Entity Framework 使用多个 DbContext 访问多个数据库服务器 类
VB.NET Entity Framework access multiple database server with several DbContext classes
我有一个测试数据库和一个实时数据库位于不同的服务器上。我目前的设计设法与两者一起工作,但我想改进访问。我现在没主意了,想听听你的意见。
问题:
如何解决以下设计问题?
我创建了两个 EF6 classes 来访问不同的数据库。 (突出显示的)
在程序启动时,我根据构建模式定义了一个默认连接。
#If DEBUG Then
myDbType = AbstractDBAccess.DatabaseType.Test
#Else
myDbType = AbstractDBAccess.DatabaseType.Live
#End If
然后我使用 myDBType 创建 DBAccess 对象来与我的数据库交互。从现在开始,它会自动注意连接到测试或实时数据库。
Dim userAccess = new UserDBAccess(myDBtype)
userAccess.GetUser()
userAccess.Dispose()
Dim projectAccess = new ProjectDBAccess(myDBType)
projectAccess.DoWork()
projectAccess.Dispose()
我在 youtube 上观看了 SW-Architecture 视频后有了这个想法 https://www.youtube.com/watch?v=sA-Hp4aBWb4 我根据自己的需要进行了修改。
到目前为止,这看起来是一种非常干净的方法,但我 运行 遇到了麻烦。
我的问题是,对于每次数据库访问,我必须 copy/paste 99% 的代码,具体取决于我要访问的服务器。例如
对于实时数据库:ctxLive < @see below code
对于测试数据库:ctxTest < @see below code
我有一个基础 class,所有 DBAccess classes 都从中派生。
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 classes。我只是不喜欢那种复制粘贴。我只需要更改 "ctxLive" 或 "ctxTest".
想象一下,有人必须在某些年内添加另一个数据库。他必须检查整个代码并为每个方法添加一个案例。
有没有更好的方法?
此处是此屏幕截图的匹配代码。
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("Whosebug"))
Case DatabaseType.Test
Me.ctxTest.CCTUsers.Where(Function(u) u.UserName.Contains("Whosebug"))
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("Whosebug"))
End Sub
End Class
以下解决方案绝对更干净,将来更易于维护。
将连接字符串添加到您的 app.config
<connectionStrings>
<add name="DB_Live" connectionString="liveDB" providerName="System.Data.EntityClient" />
<add name="DB_Test" connectionString="testDB" providerName="System.Data.EntityClient" />
</connectionStrings>
创建一个 DEBentityManager
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 的引用:
- 右键单击您的项目(不是解决方案)
- 添加 -> 引用 ... -> 框架
- 搜索 "Configuration" 并激活 "System.Configuration"
的复选框
- 点击"OK"
启动时,我根据构建模式配置连接字符串
#If DEBUG Then
connString = Configuration.ConfigurationManager.ConnectionStrings("DB_Test").ConnectionString()
#Else
connString = Configuration.ConfigurationManager.ConnectionStrings("DB_Live").ConnectionString()
#End If
我重构了我的基础 class 看起来像这样。
它现在获取连接字符串并创建 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
我为每个 table 创建了我想要的访问器
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("Whosebug")).FirstOrDefault
If IsNothing(user) Then Return False
Return True
End Function
End Class
现在我可以通过创建我的 DBAccess 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()
谢谢你给我出主意!
我有一个测试数据库和一个实时数据库位于不同的服务器上。我目前的设计设法与两者一起工作,但我想改进访问。我现在没主意了,想听听你的意见。
问题:
如何解决以下设计问题?
我创建了两个 EF6 classes 来访问不同的数据库。 (突出显示的)
在程序启动时,我根据构建模式定义了一个默认连接。
#If DEBUG Then
myDbType = AbstractDBAccess.DatabaseType.Test
#Else
myDbType = AbstractDBAccess.DatabaseType.Live
#End If
然后我使用 myDBType 创建 DBAccess 对象来与我的数据库交互。从现在开始,它会自动注意连接到测试或实时数据库。
Dim userAccess = new UserDBAccess(myDBtype)
userAccess.GetUser()
userAccess.Dispose()
Dim projectAccess = new ProjectDBAccess(myDBType)
projectAccess.DoWork()
projectAccess.Dispose()
我在 youtube 上观看了 SW-Architecture 视频后有了这个想法 https://www.youtube.com/watch?v=sA-Hp4aBWb4 我根据自己的需要进行了修改。
到目前为止,这看起来是一种非常干净的方法,但我 运行 遇到了麻烦。
我的问题是,对于每次数据库访问,我必须 copy/paste 99% 的代码,具体取决于我要访问的服务器。例如
对于实时数据库:ctxLive < @see below code
对于测试数据库:ctxTest < @see below code
我有一个基础 class,所有 DBAccess classes 都从中派生。
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 classes。我只是不喜欢那种复制粘贴。我只需要更改 "ctxLive" 或 "ctxTest".
想象一下,有人必须在某些年内添加另一个数据库。他必须检查整个代码并为每个方法添加一个案例。
有没有更好的方法?
此处是此屏幕截图的匹配代码。
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("Whosebug"))
Case DatabaseType.Test
Me.ctxTest.CCTUsers.Where(Function(u) u.UserName.Contains("Whosebug"))
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("Whosebug"))
End Sub
End Class
以下解决方案绝对更干净,将来更易于维护。
将连接字符串添加到您的 app.config
<connectionStrings>
<add name="DB_Live" connectionString="liveDB" providerName="System.Data.EntityClient" />
<add name="DB_Test" connectionString="testDB" providerName="System.Data.EntityClient" />
</connectionStrings>
创建一个 DEBentityManager
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 的引用:
- 右键单击您的项目(不是解决方案)
- 添加 -> 引用 ... -> 框架
- 搜索 "Configuration" 并激活 "System.Configuration" 的复选框
- 点击"OK"
启动时,我根据构建模式配置连接字符串
#If DEBUG Then
connString = Configuration.ConfigurationManager.ConnectionStrings("DB_Test").ConnectionString()
#Else
connString = Configuration.ConfigurationManager.ConnectionStrings("DB_Live").ConnectionString()
#End If
我重构了我的基础 class 看起来像这样。
它现在获取连接字符串并创建 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
我为每个 table 创建了我想要的访问器
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("Whosebug")).FirstOrDefault
If IsNothing(user) Then Return False
Return True
End Function
End Class
现在我可以通过创建我的 DBAccess 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()
谢谢你给我出主意!