Connection string issue in VB.NET? - vb.net

I have the following connection string class
Imports System.Data.SqlClient
Public Class DBConnection
Sub GetConnection()
Dim CrmsConn As New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("crmsConnectionString").ConnectionString)
End Sub
End Class
And I have tried to call the connection string from the above class as follows:
Dim dbcon As DBConnection
Dim con As New SqlConnection(dbcon.GetConnection())
But it has an error near dbcon.GetConnection().
What is the solution?

GetConnection is a sub. This means that it doesn't return anything and you cannot try to use an inexistant return value. (This is a compile time error, you can't produce any executable code until you fix it)
Make it a function and public
Public Function GetConnection() as SqlConnection
return New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("crmsConnectionString").ConnectionString)
End Function
and then use it as (but create the class instance first otherwise a null reference exception occurs at runtime)
' Create the instance of the DBConnection class and ...
Dim dbcon As DBConnection = new DBConnection()
' ... get the connection
Dim con as SqlConnection = dbcon.GetConnection()
Finally remember to use the Using statement around disposable objects like this
Using con = dbCon.GetConnection()
....
End Using

Related

Custom TableAdapter Delete Method Override

I'm attempting to overload the "Delete" method of a TableAdapter (approach). How can I execute an SQL statement from 'here' to handle the delete?
I've got:
Namespace AFL_BackendDataSetTableAdapters
Partial Class Log_entry_unitTableAdapter
Public Overloads Function Delete(ByVal LogEntryID As Integer) As Integer
Dim SQL As String
SQL = "DELETE FROM log_entry_unit WHERE log_entry_unit_id=" & LogEntryID
'?????.Execute SQL
Return 0
End Function
End Class
End Namespace
The overload is working fine, but I don't know how to do the hard part and actually manipulate the data from here. Previously, I've just gone into the Dataset Designer and manually updated the generated methods to work like I want them, but whenever I use the wizard to regenerate the dataset, that (as expected) gets overwritten.
I've previously only ever manipulated Data using the generated methods, and now I'm stuck.
EDIT w/ Final Answer
Based on William's help below here's the final working solution (Note I just had to use OleDb instead of SQL since my Dataset is Access:
Imports System.Data.OleDb
Namespace AFL_BackendDataSetTableAdapters
Partial Class Log_entry_unitTableAdapter
Public Overloads Function Delete(ByVal LogEntryID As Integer) As Integer
Dim queryString As String = "DELETE FROM log_entry_unit WHERE log_entry_unit_id=" & LogEntryID
Dim command As New OleDbCommand(queryString, Connection)
Dim r As Integer
Try
Connection.Open()
r = command.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.Message)
r = 0
Finally
Connection.Close()
End Try
Return r
End Function
End Class
End Namespace
I hardcoded a connection string for reference only. This should be in a config file. As an example:
Dim connectionString As String = _
"Data Source=(local);Initial Catalog=YourDatabase;" _
& "Integrated Security=true"
Dim queryString As String = "DELETE FROM log_entry_unit WHERE log_entry_unit_id=" & LogEntryID
' Create and open the connection in a using block. This
' ensures that all resources will be closed and disposed
' when the code exits.
Using connection As New SqlConnection(connectionString)
' Create the Command
Dim command As New SqlCommand(queryString, connection)
' Open the connection in a try/catch block.
Try
connection.Open()
command.ExecuteNonQuery()
Catch ex As Exception
' handle exception here
End Try
End Using
EDIT
I probably should of mentioned you will probably want to fill your adapter again after the delete.

How to create strongly typed list class in vb.net

I hate to admit this but I am new to object oriented programming in VB.NET. I have a class object called Subscriber.vb which works OK but I'd like to create a "set" or list of these objects. Could someone please help me leverage the following code to create a list of the subscribers so a "consumer" could loop through this list of subscribers? Here is what I have so far:
Public Class Subscriber
Public Sub New(ByVal theSubscriberID As Int32)
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
Try
cmd = New SqlCommand("GetSubscriberInfo_v", connection)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#SubscriberID", theSubscriberID)
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
Do While objReader.Read()
SetObjectData(objReader)
Loop
objReader.Close()
connection.Close()
Catch ex As Exception
Throw
End Try
End Sub
Private Sub SetObjectData(ByVal theObjReader As SqlDataReader)
Try
Me._ID = Convert.ToInt32(theObjReader("SubscriberID"))
Me._NameForLogon = theObjReader("SubscriberName").ToString()
Me._NameInFull = theObjReader("SubscriberNameFull").ToString()
Me._DaysUntilExpired = Convert.ToInt32(theObjReader("DaysUntilExpired"))
Me._SignupDate = theObjReader("SignupDate")
Me._ExpirationDate = theObjReader("ExpirationDate")
Me._SubscriberPhone = theObjReader("SubscriberPhone").ToString()
Me._MostRecentRenewal = theObjReader("MostRecentRenewal")
Me._CumulativeRevenue = Convert.ToDecimal(theObjReader("CumulativeRevenue"))
Me._NumberOfRenewals = theObjReader("NumberOfRenewals")
Me._SubscriptionStatusCode = theObjReader("SubscriptionStatusCode")
Me._SubscriptionStatus = theObjReader("SubscriptionStatus").ToString()
Me._NotificationStatusCode = theObjReader("NotificationStatusCode")
Me._NotificationStatus = theObjReader("NotificationStatus")
Catch ex As Exception
Throw
End Try
End Sub
End Class
I did not show the getters and setters. This has to be restricted to Visual Studio 2008 unfortunately. For a few reasons, we cannot upgrade this environment.
What would be the best practice here? Add a Public Class SubscriberList to the Subscriber.vb file or should it be a separate file? More importantly, I am stuck on how to take what I have an create a proper list. Then the caller would create an instance of the SubscriberList object. Please help me get started. Thanks.
EDIT: Here is what I came up with thanks to your idea (I'm thinking of adding some overloaded constructors which might filter the data some various ways...would that be a good practice?):
Public Class SubscriberList
Public Sub New()
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
Dim oSubscriberList As New List(Of Subscriber)
cmd = New SqlCommand("GetSubscriberInfo_v", connection)
cmd.CommandType = CommandType.StoredProcedure
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
Do While objReader.Read()
Dim id As Integer = objReader("SubscriberID")
Dim s As Subscriber = New Subscriber(id)
oSubscriberList.Add(s)
Loop
objReader.Close()
connection.Close()
End Sub
End Class
New error trying to use:
Dim allSubscribers As New SubscriberList
For Each Subscriber In allSubscribers
' allSubscribers is not declared
Next
Why not declared ? Confused rookie mistake I am sure...
EDIT (Number 2):
Changed name from SubscriberList to Subscribers plural & got this working (see below) - but I am very puzzled by the advice to remove the database connection and query from the constructor(s) and place in separate class(es). I was picturing adding overloaded constructors to Subscriber (and Subscribers). I cannot imagine how the constructors of each would get their respective data.
Public Class Subscribers
Implements IEnumerable(Of Subscriber)
#Region "properties"
Public List As New List(Of Subscriber)
#End Region
Public Function GetEnumerator() As IEnumerator(Of Subscriber) _
Implements IEnumerable(Of Subscriber).GetEnumerator
Return List.GetEnumerator()
End Function
Private Function GetEnumerator1() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return List.GetEnumerator()
End Function
Public Sub New()
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
cmd = New SqlCommand("SELECT * FROM dbo.Subscriber_v", connection)
cmd.CommandType = CommandType.Text
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
Do While objReader.Read()
Dim id As Integer = objReader("SubscriberID")
Dim s As Subscriber = New Subscriber(id)
List.Add(s)
Loop
objReader.Close()
connection.Close()
End Sub
End Class
In VB you can make a list of a custom object.
dim oSubscriberList as new List(of Subscriber)
Then you can instantiate new subscribers and add them to the list
oSubscriberList.add('add object here')
This is probably the most simple, quick and dirty way to handle it. You can also create a separate class to create a collection of your object. "Best" practices, if you want to follow SOLID programming principles and use test driven development, would point you towards making a separate collection class to deal with it, but it isnt necessary.
EDIT: as per comment below
You dont need to create a subscriberlist class. Just create a regular list of Subscribers and add them to the list as so. Do this where you are wanting to create this list (form load, some event, etc.)
Dim oSubscriberList as NEW List(of Subscriber)
Dim sConnDatabase As String = ConfigurationManager.ConnectionStrings("DatabaseConnString").ConnectionString
Dim connection As New SqlConnection(sConnDatabase)
Dim cmd As SqlCommand
cmd = New SqlCommand("SELECT * FROM dbo.Subscriber_v", connection)
cmd.CommandType = CommandType.Text
connection.Open()
Dim objReader As SqlDataReader = cmd.ExecuteReader()
while objReader.Read()
oSubscriberList.Add(New Subscriber(objReader("SubscriberID"))
end while
'additional cleanup steps here
Then you can just iterate over you list as so:
For each sub as Subscriber in oSubscriberList
'do something
Next

Declaration Expected

Good day all. Please advise me
Why I got an error message "Declaration Expected" when put the cursor on cmd variable. What Should I do?! .. the code appears below:
Imports System.Data.Sqlclient
Imports System.Configuration
Partial Class _Default
Inherits Page
Private Shared Connectionstr As String ="DataSource=localhost;initialCatalog=Orders;Integrated Security=true"
Dim conn As SqlConnection = New SqlConnection(Connectionstr)
Dim cmd As SqlCommand = conn.CreateCommand()
cmd.CommandText="SELECT * FROM dbo.Customers"
End Class
You are attempting to use the variable command outside a Property, Function, or Method. At the very least, try wrapping your command in a method (Sub) which performs the desired action with the data:
Partial Class _Default
Inherits Page
Private Sub DoSomethingWithCustomers()
Dim conn As SqlConnection = New SqlConnection(Connectionstr)
Dim cmd As SqlCommand = conn.CreateCommand()
cmd.CommandText = "SELECT * FROM dbo.Customers"
conn.Open()
Dim dr = cmd.ExecuteReader()
' Do something with the data returned . . .
' ...
' Now Cleanup:
conn.Close()
cmd.Dispose()
conn.Dispose()
End Sub
The above can be improved by wrapping your data access objects in Using blocks, which handle proper disposal of unmanaged resources for you:
Private Sub DoSomethingBetterWithCustomers()
Dim SQL As String = "SELECT * FROM dbo.Customers"
Using conn As New SqlConnection(Connectionstr)
Using cmd As New SqlCommand(SQL, conn)
conn.Open()
Dim dr = cmd.ExecuteReader()
' Do something with the data returned
' . . .
dr.Close()
End Using ' Using Block takes carre of Disposing SqlCommand
End Using ' Using Block takes care of Closing and Disposing Connection
End Sub
Beyond that, it is difficult to know what, precisely, you are trying to do with your code, so the two examples above are really, really basic and general.

VB.NET Returning an Object

Will the following statement cause a memory leak:
Imports System.Data.SQLClient
Public Function getConnection () As SQLConnection
return New SQLConnection()
End Function
Public Sub TestConnection()
Dim con As SQLConnection
con = getConnection
con.close
con = Nothing
End Sub
How does .close or .dispose get called on the SQLConnection in getConnection?
You're returning a reference type, hence you operate on the same instance in TestConnection so no memory leak here.
At the end you have 2 instances with null (gc will collect them), but the connection is closed.
There will be no memory leak because it will be garbage collected after you've called the method.
But this method does nothing but causing confusion. You should always dispose connections(which closes it implicitely) as soon as you're finished with it (even in case of an exception).
You can do that in a finally of a Try/Finally or (easier) with the Using statement. But since both approaches need to wrap the connection, your method enables the calling method to forget it. Therefore it is bad practise.
So simply do this:
Public Sub TestConnection()
Using con = New SqlConnection("connection string here")
Using cmd = new SqlCommand("sql query here", con)
' do something, f.e. cmd.ExecuteNonQuery() '
End Using
End Using
End Sub

Setting the database connection when using a TransactionScope

Does the database connection have to be set inside a TransactionScope?
Or can I set it in the ctor and then have instance methods create up a TransactionScope?
EDIT: e.g.
Public Sub New()
Dim conn = new SqlConnection(...connection string)
Public Sub SomeClassMethod()
using ts as new TransactionScope
//conn has already been initialized
//so, here you can set commands, ExecuteDataSet, etc.
vs
Public Sub New()
//nothing here
Public Sub SomeClassMethod()
using ts as new TransactionScope
conn = new SqlConnection(...connection string)
set commands, ExecuteDataSet, etc.
the question is do you need to create the connection to the database after you've created a TransactionScope or can it be done before?
If you want you SqlConnection to be under transaction, than you need to create it under TransactionScope.
using(TransactionScope scope = new TransactionScope())
{
SqlConnection x = new SqlConnestion("....");
x.Open();
....your code... SQlCommands etc....
x.Close();
scope.Complete();
}