I recently had the chance to immerse myself in doing CLR development on Sql Server 2005. The project I'm working on requires some complex pricing algorithms for varying combinations of products and doing the calculations in a "set-based" way just didn't feel right.
I needed to write several closely related stored procedures and did so in a single project. When you create each procedure, Visual Studio creates a separate file for each procedure, but the files declare the class using the partial keyword which means that each procedure is actually just a static (shared) method on a single class. As work progressed, I saw a number of opportunities to reuse some of the methods I had written across procedures. This was easy enough since all the procs were actually in the same class...even private members we accessible from all the procedures.
At some point, however, I realized that I needed to call one procedure from another. This presented a problem, though. I typically started all my procedure like this...
Partial Public Class StoredProcedures
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub up_MyProc(ByVal parm1 As Integer, ByVal parm2 As Integer)
Dim conn As New SqlConnection("Context Connection=true")
conn.Open()
. . . .
So, at the entry point of the first procedure, I opened a Context Connection and as soon as I called into the second proc, it tried to create another connection. Since only one context connection is allowed per call, the attempt to open the second one failed. I could, of course, call into the second procedure by creating a SqlCommand and executing it, but that feels dirty considering that both procs are actually in the same class.
So, after some thought, I determined a pattern that I intend to use from now on in such situations. For all my CLR procs, the method that is the entry point for the procedure will be structured like this...
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub up_DoWork(ByVal parm1 As Integer, ByVal parm2 As Integer)
Dim conn As New SqlConnection("Context Connection=true")
conn.Open()
DoWork(parm1, parm2, conn)
conn.Close()
End Sub
Now, I can call the code as a stored procedure (through up_DoWork), which is its primary purpose, and also call into the whole of the proc's functionality (DoWork) while passing in a context connection created in another proc.