I am seeing the following error when I attempt to open the second connection in the code below: Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool.
Public Function Test()
Using Scope = New TransactionScope
getMailServer()
getMailServer()
End Using
End Function
Private Function getMailServer() As String
Dim objCommand As SqlCommand, objCommand2 As SqlCommand
Dim objCon As SqlConnection
Dim intDeleteCount As Integer
Dim objDR As SqlDataReader
Dim strServer As String
Try
objCommand = New SqlCommand
objCommand2 = New SqlCommand
objCon = New SqlConnection(_ConString) 'taken from web.config
objCon.Open()
objCommand.Connection = objCon
Using objCon
Using objCommand
objCommand2.Connection = objCon
objCommand2.CommandText = "SELECT SMTPServer FROM dbServer"
objDR = objCommand2.ExecuteReader
Do While objDR.Read
strServer = objDR("SMTPServer")
Loop
objDR.Close()
End Using
End Using
Return strServer
Catch ex As Exception
Throw
Finally
End Try
End Function
Please note that I have spent some time Googling this and I have tried a few things posted on this website e.g. restarting the districuted transaction coordinator in Services. I did also read somewhere that using TransactionScope should be avoided with distributed transactions (those with multiple connection objects). I am not sure if this is true.
You can use TransactionScope for distributed transactions. In fact, by introducing TransactionScope in .NET 2.0, Microsoft put COM+ out of its misery. It was a very good move, COM+ was awful.
You need to configure DTC for network access on all machines participating in the transaction - the one running your code, as well as those running the databases (or other resources you may be using, such as MSMQ).
Here's how to enable DTC network access.
Related
Please have a look at the code below:
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Dim objCommand As SqlCommand
Dim objCon As SqlConnection
Dim p1 As Person
Try
p1 = New Person
p1.DoSomething()
objCommand = New SqlCommand
Using objCommand
Dim strConString As String = "Data Source=IANSCOMPUTER;Initial Catalog=Test;Integrated Security=True"
objCon = New SqlConnection
Using objCon
objCon.ConnectionString = strConString
objCon.Open()
objCommand.Connection = objCon
objCommand.CommandText = "select startdate from person "
Dim objDR As SqlDataReader = objCommand.ExecuteReader
If objDR.HasRows Then
objDR.Read()
Using objCon
Dim startdate As String = objDR("startdate")
End Using
End If
End Using
End Using
Catch ex As Exception
Throw
Finally
If objCon.State = ConnectionState.Open Then
objCon.Close()
End If
objCon = Nothing
objCommand = Nothing
p1=Nothing 'This line is still needed
End Try
End Sub
I understand that the code in the finally clause is pointless because the connection and command are wrapped in Using statements.
However what happens if you have your own custom classes like Person, which doesn't use unmanaged resources? Surely the FINALLY clause would be needed in this instance to ensure that the reference to the object (on the heap) is set to nothing regardless of whether an exception is thrown or not?
When objects are referenced from a method, there is no need to set the variables to Nothing, since the objects will be "unrooted" and available for garbage collection as soon as the method call ends. When the method call ends all the local variables on the stack will be gone and the object they refer to will have no rooted references to them, making them available for garbage collection. In general you don't need to "null out" (by setting them to Nothing in vb.net) variables in .NET, since it does not rely on reference counting for managing objects on the heap.
Have a look at this article for an overview of how allocation and deallocation of memory works in .NET.
I am a developer building websites in VB.Net using Visual Studio 2010. I am trying to populate some fields when a user visits a website based on their decisions on a previous screen.
My connection information is as follows:
Dim myDataReader As SqlDataReader
Dim myConnection As SqlConnection
Dim myCommand As SqlCommand
Dim strSQL As String
myConnection = New SqlConnection("Data Source=localhost\sqlexpress; Database=PREP; Integrated Security=SSPI;")
Try
myConnection.Open()
Catch ex As Exception
MsgBox(ex.Message)
End Try
strSQL = "SELECT * FROM Charts where ID=1"
myCommand = New SqlCommand(strSQL, myConnection)
myDataReader = myCommand.ExecuteReader()
If myDataReader.Read() Then
TextBox1.Text = myDataReader.Item("Priority1")
Else
MsgBox("Didn't work...")
End If
The error I continue to get is:
Cannot open database "PREP" by the login. The login failed. Login failed for user 'OR-AA-Me\Me'
I assumed that since it was a local database I would not need a username and password. Am I wrong?
Also, are there glaring practices in the above code that will be unwise when I transport this to a commercial environment?
Thanks!
Solved:
The connection string simply needed additional filepath information.
The successful connection information was:
myConnection = New SqlConnection("Data Source=.\SQLEXPRESS; AttachDbFilename=|DataDirectory|\PREP.mdf; Integrated Security=True; User Instance=True")
There was no need for a username as the Integrated Security set to True assumes that the computer will use the login information for the user on the actual computer he is using.
I have been using SQLDataReader for fetchig some data from a db. Once I used Reader with the the connection I am closing the connection only and not the Reader. Do we have any possibility of connection leak
Here is the code that I am using
Public Sub Get_SomeData(ByVal sCon As String,ByRef ObjectToReturn As SomeClass)
Dim sqlCon As SqlConnection = New SqlConnection(sCon)
Dim sqlR As SqlDataReader = Nothing
Dim sqlCmd As SqlCommand = New SqlCommand
sqlCmd.CommandType = CommandType.StoredProcedure
sqlCmd.Connection = sqlCon
sqlCmd.CommandText = "get_SomeData"
sqlCon.Open()
sqlR = sqlCmd.ExecuteReader(CommandBehavior.CloseConnection)
If sqlR.HasRows And sqlR.Read Then
ObjectToReturn.Property1 = sqlR("Column1").ToString
ObjectToReturn.Property1 = sqlR("Column1").ToString
ObjectToReturn.Property1 = sqlR("Column1").ToString
ObjectToReturn.Property1 = sqlR("Column1").ToString
End If
sqlCon.Close()
End Sub
No, closing the connection will suffice, but a better approach is through the Using statement
Using sqlCon = New SqlConnection(sCon)
Dim sqlR As SqlDataReader = Nothing
Using sqlCmd = New SqlCommand
sqlCmd.CommandType = CommandType.StoredProcedure
sqlCmd.Connection = sqlCon
sqlCmd.CommandText = "get_SomeData"
sqlCon.Open()
Using sqlR = sqlCmd.ExecuteReader()
If sqlR.HasRows And sqlR.Read Then
ObjectToReturn.Property1 = sqlR("Column1").ToString
.......
End If
End Using
End Using
End Using
The important part in MSDN docs about Using
Sometimes your code requires an unmanaged resource, such as a file
handle, a COM wrapper, or a SQL connection. A Using block guarantees
the disposal of one or more such resources when your code is finished
with them. This makes them available for other code to use.
Managed resources are disposed of by the .NET Framework garbage
collector (GC) without any extra coding on your part. You do not need
a Using block for managed resources. However, you can still use a
Using block to force the disposal of a managed resource instead of
waiting for the garbage collector.
I am using this code to get data:
Dim connetionString As String
Dim connection As SqlConnection
Dim sqlq As String
sqlq = "select top 1 * from table1 where smth"
Dim ds As New DataSet
connetionString = "Data Source=db;Initial Catalog=ic;User ID=id;Password=pass"
connection = New SqlConnection(connetionString)
Try
Using connection
Dim command As SqlCommand = New SqlCommand(sqlq, connection)
connection.Open()
Dim reader As SqlDataReader = command.ExecuteReader()
If reader.HasRows Then
Do While reader.Read()
x = reader.GetString(5)
Loop
End If
reader.Close()
End Using
Catch ex As Exception
End Try
This type of connection (with different sqlq [query]) I use a lot in diffenrent functions and every time I close the connection. I want to optimize it so it would take less time to get data. How do I do that?
It is best practise to always dispose/close a connection as soon as you're finished with it. Actually the connection-pool will not close the underlying physical connection but only flag this connection as reusable if it is closed. So if you don't close a connection it cannot be reused, hence the pool needs to create a new physical connection which is very expensive.
So only some minor improvements:
Const sql = "select top 1 * from table1 where smth"
Dim table As New DataTable()
Using con = New SqlConnection("Data Source=db;Init ....")
Using command = New SqlCommand(sql, con)
Using da= New SqlDataAdapter(command)
da.Fill(table)
End Using
End Using
End Using
You should use Using for any object implementing IDisposable. You should not use an empty Catch block.
Use connection pooling instead.
By default as long as the connection string is the same, connections will be taken from the same connection pool.
Shortly connection pool keeps not needed connections open, and return that connections on the next request, so you don't need to think about the time it take to open connection.
Keeping connections open for longer than you needed is bad idea, because it costs resources, and in general some servers can accept limited connections.
I develop a lot in ASP.NET and I know that you can only open one SQLDataReader for each SQLConnection. However, this does not appear to be the case in VB.NET (form application) i.e. I have opened multiple SQLDataReaders for one connection object. Is this allowed in VB.NET?
If there is not an obvious answer to this then I will post some code.
Here is some code:
Public Function CheckActiveReviews()
Dim objCon As SqlConnection
Dim objCommand As SqlCommand, objCommand2 As SqlCommand
Dim objDR As SqlDataReader, objDR2 As SqlDataReader
Try
objCon = New SqlConnection("Data Source=TestDatabase;Initial Catalog=TestTable;User ID=TestUser;Password=TestPassword;MultipleActiveResultSets=True")
objCommand = New SqlCommand
objCommand.Connection = objCon
objCommand2 = New SqlCommand
objCommand2.Connection = objCon
objCon.Open()
objCommand.CommandText = "SELECT ID FROM Person WHERE PersonID > 1000"
objDR = objCommand.ExecuteReader()
Do While objDR.Read
objCommand2.CommandText = "SELECT * FROM Sport WHERE PersonID = #PersonID "
objCommand2.Parameters.AddWithValue("#PersonID", objDR("ID"))
objDR2 = objCommand2.ExecuteReader
Loop
Catch ex As Exception
End Try
End Function
You can use multiple data readers if you use MARS - Multiple Active Result Sets - but I wouldn't advise that unless you really need it.
Instead, I'd suggest creating a new SqlConnection object each time you need it - use it for as short a period as you can, then dispose of it (use a Using statement to do this for you). The connection pool will take care of the efficiency in terms of reusing "physical" network connections where possible. That way you don't need to worry about whether the SqlConnection is already open etc - you just always follow the same "create, open, use, dispose" pattern every time.