M
Mike Hofer
In a large application I'm working on (ASP.NET 1.1, VS2003), we have a
base class that wraps stored procedures. Essentially, this base class
(StoredProcedureBase) encapsulates the code to set up the connection,
transaction, command and parameters required to invoke a stored
procedure on our SQL Server database. It provides helper methods that
simplify the process of invoking the stored procedure so that our data
access classes can make the call like this:
Public Function GetBuildings(ByVal siteId As Integer) As
BuildingCollection
Dim buildings As BuildingCollection
Dim connection As SqlConnection
Try
connection = ConnectionGenerator.GetOpenConnection()
buildings = GetBuildingsProcedure.Execute(siteId, connection)
Finally
Disposer.DisposeOf(connection)
End Try
Return buildings
End Function
The stored procedure classes derive from StoredProcedureBase and look
like this:
Public NotInheritable Class GetBuildingsProcedure
Inherits StoredProcedureBase
Private Sub New(ByVal siteId As Integer, ByVal connection As
SqlConnection)
MyBase.New("GetBuildings", connection)
AddParameter("@SiteID", SqlDbType.Int).Value = siteId
End Sub
Public Shared Function Execute(ByVal siteId As Integer, ByVal
connection As SqlConnection)
ValidateOpenConnection(connection)
If siteId <= 0 Then Throw New
ArgumentOutOfRangeException("siteId")
Dim procedure As GetBuildingsProcedure
Dim buildings As BuildingCollection
Dim building As Building
Dim reader As SqlDataReader
Try
procedure = New GetBuildingsProcedure(siteId, connection)
reader = procedure.ExecuteReader()
buildings = New BuildingCollection
Do While reader.Read()
building = New Building()
Store(reader("ID"), -1, building.ID)
Store(reader("AcceptsAdmissions"), False,
building.AcceptsAdmissions)
Store(reader("Description"), String.Empty,
building.Description)
Store(reader("Name"), String.Empty, building.Name)
buildings.Add(building)
Loop
Finally
Disposer.DisposeOf(reader, procedure)
End Try
Return buildings
End Function
End Class
What we like about this model is that it provides *one* place to
invoke the stored procedure, and that it's got really high functional
cohesion. What worries me, however, is that it appears to be tightly
coupled to the Building class. However, it takes very little code to
invoke the stored procedure, and the result set is type-safe.
But the tight coupling is bugging me. It's this annoying little voice
nagging at me in the back of my head. The previous versions of this
class weren't this typesafe, but they weren't so tightly coupled
either. But with that lack of coupling came a lot of code. Refactoring
the code to reduce code complexity resulted in this model; it's only
after looking at the model that we realized we were now tightly
coupled.
However, I'm wondering if the tight coupling isn't worth the reduction
in code duplication. My gut tells me that it is, simply from a
reduction in code complexity and the corresponding ease of
maintenance.
So here are my questions to you folks:
1. Would you do it this way, or would you suggest something else?
2. Do you see any problems with this model?
3. Is the tight coupling worth the trade-off for the reduction in code
complexity and ease of maintenance?
4. Am I missing other concerns that should be taken into account?
I work in a vaccuum here; I am the lone developer at my company, so I
don't have any peer developers to bounce ideas off of. So this is a
desperate attempt to seek input from others with experience. Any
guidance you folks can provide would be greatly appreciated.
Thanks in advance,
Mike
base class that wraps stored procedures. Essentially, this base class
(StoredProcedureBase) encapsulates the code to set up the connection,
transaction, command and parameters required to invoke a stored
procedure on our SQL Server database. It provides helper methods that
simplify the process of invoking the stored procedure so that our data
access classes can make the call like this:
Public Function GetBuildings(ByVal siteId As Integer) As
BuildingCollection
Dim buildings As BuildingCollection
Dim connection As SqlConnection
Try
connection = ConnectionGenerator.GetOpenConnection()
buildings = GetBuildingsProcedure.Execute(siteId, connection)
Finally
Disposer.DisposeOf(connection)
End Try
Return buildings
End Function
The stored procedure classes derive from StoredProcedureBase and look
like this:
Public NotInheritable Class GetBuildingsProcedure
Inherits StoredProcedureBase
Private Sub New(ByVal siteId As Integer, ByVal connection As
SqlConnection)
MyBase.New("GetBuildings", connection)
AddParameter("@SiteID", SqlDbType.Int).Value = siteId
End Sub
Public Shared Function Execute(ByVal siteId As Integer, ByVal
connection As SqlConnection)
ValidateOpenConnection(connection)
If siteId <= 0 Then Throw New
ArgumentOutOfRangeException("siteId")
Dim procedure As GetBuildingsProcedure
Dim buildings As BuildingCollection
Dim building As Building
Dim reader As SqlDataReader
Try
procedure = New GetBuildingsProcedure(siteId, connection)
reader = procedure.ExecuteReader()
buildings = New BuildingCollection
Do While reader.Read()
building = New Building()
Store(reader("ID"), -1, building.ID)
Store(reader("AcceptsAdmissions"), False,
building.AcceptsAdmissions)
Store(reader("Description"), String.Empty,
building.Description)
Store(reader("Name"), String.Empty, building.Name)
buildings.Add(building)
Loop
Finally
Disposer.DisposeOf(reader, procedure)
End Try
Return buildings
End Function
End Class
What we like about this model is that it provides *one* place to
invoke the stored procedure, and that it's got really high functional
cohesion. What worries me, however, is that it appears to be tightly
coupled to the Building class. However, it takes very little code to
invoke the stored procedure, and the result set is type-safe.
But the tight coupling is bugging me. It's this annoying little voice
nagging at me in the back of my head. The previous versions of this
class weren't this typesafe, but they weren't so tightly coupled
either. But with that lack of coupling came a lot of code. Refactoring
the code to reduce code complexity resulted in this model; it's only
after looking at the model that we realized we were now tightly
coupled.
However, I'm wondering if the tight coupling isn't worth the reduction
in code duplication. My gut tells me that it is, simply from a
reduction in code complexity and the corresponding ease of
maintenance.
So here are my questions to you folks:
1. Would you do it this way, or would you suggest something else?
2. Do you see any problems with this model?
3. Is the tight coupling worth the trade-off for the reduction in code
complexity and ease of maintenance?
4. Am I missing other concerns that should be taken into account?
I work in a vaccuum here; I am the lone developer at my company, so I
don't have any peer developers to bounce ideas off of. So this is a
desperate attempt to seek input from others with experience. Any
guidance you folks can provide would be greatly appreciated.
Thanks in advance,
Mike