this is in my OfficeEquipment.Frm
Public Function Loadfunction()
dt = Functions.LoadData()
End Function
and this is the error for the above code
Warning 1 Function 'Loadfunction' doesn't return a value on all code paths. A null reference exception could occur at run time when the result is used. C:\Documents and Settings\IJDinglasan\My Documents\Visual Studio 2008\Projects\Electronic Office Equipment History\Electronic Office Equipment History\Update Office Equipment Profile.vb 9 5 Electronic Office Equipment History
this is in my module Functions
Private Function LoadData() As DataTable
Using sqlconn = New SqlClient.SqlConnection("server = SKPI-APPS1;" & _
"Database = EOEMS;integrated security=true")
Dim dt As New DataTable
sqlconn.Open()
Dim da As New SqlDataAdapter("SELECT * FROM tblOfficeEquipmentProfile", sqlconn)
da.Fill(dt)
Return dt
End Using
End Function
Basically just use the class and the function you have....
Dim dt As DataTable
dt = yourclass.LoadData()
Now dt is your table that you can use where you like.
MrCoDeXeR
EDITS
Where ever you have your function (LoadData) you need to reference that class and the function. For example: say my main class is: frmMain.vb and my class that has my function is: frmStudents I want to get that function.
So.... on frmMain.vb you need to declare another DataTable and assign it.... see below...
Dim dt As DataTable
dt = frmStudents.LoadData()
We call the function from frmStudents and fill our new table with our data. What you need to do is set a breakpoint on: dt = frmStudents.LoadData() and run your solution. When you get to that line press F-11 and see if it jumps over to you other class that has your function. then press F-11 and continue to step-through and see if it throws an error. On your: Return dt in your function, hover over this if it makes it this far and click the magnifying glass and see if data exists or has your column names, if so your good to go...
Related
I've got a DataTable in DataSet which is filled on Form's Load event with some data from an SQL database.
I've added a Module where I am creating a function which will utilize the data from the DataTable.
Whilst I am able to get row data from Form's code, I am not able to access it from within the Module which I am guessing has something to do with references to a DataSet/DataTable.
I am typing below from top of my head...
Dim dt as Datatable
Dim dr() as Datarow
Dim DataSet1 as Dataset = New DataSet1
dt = DataSet1.comm_rates
dr = dt.select("fieldName='somevalue'")
Return a = dr(0)("fieldA")
Any help would be much appreciated.
Supposing DataSet1 is inside Class Form1, qualify your reference, e.g
Dim ds1 = Form1.DataSet1
dt = ds1.comm_rates
Beginner here
I have the following code which I would like to call using a button called findCustomerBTN
Public Function Execute(ByVal sqlQuery As String) As ADODB.Recordset
If SecuritySSPIchkbx.Checked Then
chk = "TRUE"
Else chk = "FALSE"
End If
builder.DataSource = ServerBox.Text
builder.InitialCatalog = DatabaseBox.Text
builder.UserID = Username.Text
builder.Password = Password.Text
builder.IntegratedSecurity = chk
MessageBox.Show(builder.ConnectionString)
Using sqlConnection1 As New SqlConnection(builder.ConnectionString)
sqlConnection1.Open()
Try
command = New SqlCommand(sqlQuery, sqlConnection1)
adapter.SelectCommand = command
adapter.Fill(ds, "Create DataView")
adapter.Dispose()
command.Dispose()
sqlConnection1.Close()
dv = ds.Tables(0).DefaultView
DataGridView1.DataSource = dv
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Using
End Function
How do I call this function:
Private Sub findCustomerBTN_Click(sender As Object, e As EventArgs) Handles
sqlquery = "Select * from customers where name = 'Smith'"
call function?
End Sub
I have googled but I can't wrap my head around how a function works any pointers to help me understand would be great thanks
In VB, a function is a block of code that returns a value. Your code does not return a value, and the type of query execution you're carrying out will never return an ADODB.RecordSet - that's an ancient technology remeniscent of the VB6 era, and you're using a much more modern data access strategy (ADO.NET, DataTables and DataAdapter) though it's not the latest and greatest.
To offer a run through of your code, and the other issues it has:
Execute is a pretty bland name - go for something more specific, just incase you run the wrong execute and some poor prisoner ends up in front of the firing squad
Your function takes an sql string as a parameter to run, but then overwrites it with a fixed string, so there isn't much point offering it as a parameter in the first place. I could call Execute("SELECT * FROM kittens") expecting to get some cute data back, and all I get is the same old customer
Avoid calling MessageBox.Show in any code that shoudl reasonably be expected to run quietly and repeatedly, otherwise the user is going to get hella annoyed. If youre putting this here for debugging purposes, learn how the visual studio debugger works instead
Your code runs an sql query and assigns the resulting data table data to the datasource of a grid, so that the grid will show the data. There's absolutely no need for this code to be a function (and in c# it wouldnt even compile because it doesn't return a value
What are functions? What do they do? They take some inuts and return some outputs:
Public Function AddTheseTwo(a as Integer, b as Integer) As Integer
Return a + b
End Function
They are called like this:
Dim sum = AddTheseTwo(2, 3)
I.e. you give the name of the function and the input values, which can be variables, and store the result (usually, because you want to use it). Here's a code of yours that is a sub - a block of code that doesn't return a value
Private Sub findCustomerBTN_Click(sender As Object, e As EventArgs) Handles
Execute("Select * from customers where name = 'Smith'")
End Sub
It's not linked to your button click, because there's nothing afte rthe Handles keyword. It should be something like Handles findCustomerBTN.Click. You can mash that button all day and nothing will happen
It called Execute but didn't store the return value (because it didn't need to, because Execute doesn't return anything, so Execute should have been declared as a sub, not a function)
Edit:
You mentioned you want the function to return a datatable:
Public Function GetDataTable(ByVal sqlQuery As String) As DataTable 'need to Imports System.Data if you haven't already
If SecuritySSPIchkbx.Checked Then
chk = "TRUE"
Else chk = "FALSE"
End If
'better to declare builder in this function, not elsewhere
builder.DataSource = ServerBox.Text
builder.InitialCatalog = DatabaseBox.Text
builder.UserID = Username.Text
builder.Password = Password.Text
builder.IntegratedSecurity = chk
MessageBox.Show(builder.ConnectionString)
Using sqlConnection1 As New SqlConnection(builder.ConnectionString)
sqlConnection1.Open()
Try
'note: better to declare adapter and command in this function too
command = New SqlCommand(sqlQuery, sqlConnection1)
adapter.SelectCommand = command
Dim dt as New DataTable
adapter.Fill(dt)
adapter.Dispose()
command.Dispose()
sqlConnection1.Close()
Return dt
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Using
Return Nothing 'a function has to return something from all possible code paths, even if it's Nothing :)
End Function
And then you call it like this, perhaps:
Private Sub findCustomerBTN_Click(sender As Object, e As EventArgs) Handles whateverbutton.Click
'you can set a datatable as a datasource, doesn't have to be the datatable.defaultview
myDataGRidView.DataSource = GetDataTable("Select * from customers where name = 'Smith'")
End Sub
I recommend you turn on the options for Strict/Explicit etc, to encourage better coding practices. By default VB is quite loose, letting you use variables that havent been declared (autodeclaring variable names that are a typo of another variable name etc), automatically returning Nothing for you from functions etc - it's these little auto's that will later lead to bugs and frsutrations. Computer programming si a precise art; turn on all options to force yourself to be as precise as possible
You can call Execute function using this code:
Private Sub findCustomerBTN_Click(sender As Object, e As EventArgs) Handles
Execute("Select * from customers where name = 'Smith'")
End Sub
You also have to remove this line from Execute function:
sqlQuery = ("select * from ac_billbook where ref = '900123'")
Please follow Steve suggestion to read a good book about programming in VB.NET.
i work in vb.net project using 3 tier architecture
i have class BL include function name : show all customer and this is the code :`
Public Function ShowCustomer() As Customer()
Dim sql As String
Dim emps(-1) As Customer
Dim e1 As Customer
sql = "select Customer_name from Customer"
Dim dr As SqlDataReader = OBJECT_M.Exe_SQL(sql)
While dr.Read
e1 = New Customer
e1.Customer_Name = dr(0)
ReDim Preserve emps(UBound(emps) + 1)
emps(UBound(emps)) = e1
End While
Return emps
End Function
now in interface i need to handle all Customer name and write the name in the listview
my code:
Dim obj As New BL
Dim obj2 As New Customer
Dim x As Integer = 1
While x <> obj.ShowCustomer.Length
lb.Items.Add(obj.ShowCustomer(x).Customer_Name.ToString())
End While
but i have error message talk about this :
Additional information: The connection was not closed. The connection's current state is open.
please can Anybody save my day ?
For SqlConnection, SqlCommand, SqlDataReader, DataTable, DataSet (and any other disposable object) make sure to Dispose() of the object when you are done.
If you don't call Dispose() (or Close() in this case) connections will remain open and you will get memory and handle leaks.
The easist way is to use the Using keyword (which will also dispose in the case of an exception or other short circuiting event:
Using dr As SqlDataReader = OBJECT_M.Exe_SQL(sql)
While dr.Read
e1 = New Customer
e1.Customer_Name = dr(0)
ReDim Preserve emps(UBound(emps) + 1)
emps(UBound(emps)) = e1
End While
End Using
Make sure to do the same in the object I have detailed above in OBJECT_M.Exe_SQL, once you have called Dispose()/Close() on an oject you will not be able to use the instance of the object again and will have to create a new instance.
Refer to the documentation for more examples: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader(v=vs.110).aspx
Also while there is nothing wrong with using arrays, you may find it easire to use a List(of T) which you can later convert to an using ToArray().
I have a question about database values and how to determine the id of a value that has been changed by the user at some point.
As it is currently set up there is a combobox that is populated from a dataset, and subsequent text boxes whose text should be determined by the value chosen from that combobox.
So let's say for example you select 'Company A' from the combobox, I would like all the corresponding information from that company's row in the dataset to fill the textboxes (Name = Company A, Address = 123 ABC St., etc.,)
I am able to populate the combobox just fine. It is only however when I change the index of the combobox that this specific error occurs:
An unhandled exception of type 'System.Data.OleDb.OleDbException'
occurred in System.Data.dll
Additional information: Data type mismatch in criteria expression.
Here is the corresponding code:
Imports System.Data.OleDb
Public Class CustomerContact
Dim cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|datadirectory|\CentralDatabase.accdb;")
Dim da As New OleDbDataAdapter()
Dim dt As New DataTable()
Private Sub CustomerContact_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cn.Open()
da.SelectCommand = New OleDbCommand("select * from Customers", cn)
da.Fill(dt)
Dim r As DataRow
For Each r In dt.Rows
cboVendorName.Items.Add(r("Name").ToString)
cboVendorName.ValueMember = "ID"
Next
cn.Close()
End Sub
Private Sub cboVendorName_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboVendorName.SelectedIndexChanged
cn.Open()
da.SelectCommand = New OleDbCommand("select * from Customers WHERE id='" & cboVendorName.SelectedValue & "'", cn)
da.Fill(dt)
Dim r As DataRow
For Each r In dt.Rows
txtNewName.Text = "Name"
txtAddress.Text = "Address"
Next
cn.Close()
End Sub
The error is caught at Line 24 of this code, at the second da.Fill(dt) . Now obviously from the exception I know that I am sending in a wrong datatype into the OleDbCommand, unfortunately I am a novice when it comes to SQL commands such as this. Also please keep in mind that I can't even test the second For loop, the one that is supposed to fill the Customer information into textboxes (for convenience I only copied the first two textboxes, of which there are nine in total). I am think I could use an If statement to determine if the row has been read, and from there populate the textboxes, but I will jump that hurdle when I can reach it.
Any guidance or suggestions would be much appreciated. Again I am a novice at managing a database and the code in question pertains to the project my current internship is having me write for them.
Since you already have all the data from that table in a DataTable, you dont need to run a query at all. Setup in form load (if you must):
' form level object:
Private ignore As Boolean
Private dtCust As New DataTable
...
Dim SQL As String = "SELECT Id, Name, Address, City FROM Customer"
Using dbcon = GetACEConnection()
Using cmd As New OleDbCommand(SQL, dbcon)
dbcon.Open()
dtCust.Load(cmd.ExecuteReader)
End Using
End Using
' pk required for Rows.Find
ignore = True
dtCust.PrimaryKey = New DataColumn() {dtCust.Columns(0)}
cboCust.DataSource = dtCust
cboCust.DisplayMember = "Name"
cboCust.ValueMember = "Id"
ignore = False
The ignore flag will allow you to ignore the first change that fires as a result of the DataSource being set. This will fire before the Display and Value members are set.
Preliminary issues/changes:
Connections are meant to be created, used and disposed of. This is slightly less true of Access, but still a good practice. Rather than connection strings everywhere, the GetACEConnection method creates them for me. The code is in this answer.
In the interest of economy, rather than a DataAdapter just to fill the table, I used a reader
The Using statements create and dispose of the Command object as well. Generally, if an object has a Dispose method, put it in a Using block.
I spelled out the columns for the SQL. If you don't need all the columns, dont ask for them all. Specifying them also allows me to control the order (display order in a DGV, reference columns by index - dr(1) = ... - among other things).
The important thing is that rather than adding items to the cbo, I used that DataTable as the DataSource for the combo. ValueMember doesn't do anything without a DataSource - which is the core problem you had. There was no DataSource, so SelectedValue was always Nothing in the event.
Then in SelectedValueChanged event:
Private Sub cboCust_SelectedValueChanged(sender As Object,
e As EventArgs) Handles cboCust.SelectedValueChanged
' ignore changes during form load:
If ignore Then Exit Sub
Dim custId = Convert.ToInt32(cboCust.SelectedValue)
Dim dr = dtCust.Rows.Find(custId)
Console.WriteLine(dr("Id"))
Console.WriteLine(dr("Name"))
Console.WriteLine(dr("Address"))
End Sub
Using the selected value, I find the related row in the DataTable. Find returns that DataRow (or Nothing) so I can access all the other information. Result:
4
Gautier
sdfsdfsdf
Another alternative would be:
Dim rows = dtCust.Select(String.Format("Id={0}", custId))
This would return an array of DataRow matching the criteria. The String.Format is useful when the target column is text. This method would not require the PK definition above:
Dim rows = dtCust.Select(String.Format("Name='{0}'", searchText))
For more information see:
Using Statement
Connection Pooling
GetConnection() method aka GetACEConnection
I'm doing .NET 3.5 programming in VB for a class. I have a .mdb database with 3 related tables, and a table adapter with some queries on it that look like this:
SELECT PropertyID, Street, Unit, City, Zip, Type, Bedrooms, Bathrooms, Area, MonthlyRent
FROM tblProperties
Then in a form i have a DataGridView. What i want to do is take the data that is returned from the query and display it in the DGV. However, when i do this, it displays all 35 columns in the database, not the 10 i selected (The ten are the only ones that have data in them however... so it's basically a table with a bunch of blank columns).
My current, inelegant solution is to return the query to a DataTable, then iterate through the table's columns, deleting the one's i dont want. This is not robust, efficient, and does not like me delete the primary key column.
My TA suggested trying to use an untyped databinding... he said this should display only the data I pull, but neither of us has been able to figure this out yet.
Thank You!
UPDATE
I'm not sure what you mean by the .aspx/.aspx.vb pages, but this is the query code i have from the table adapter
SELECT tblRent.PaymentID, tblTenant.TenantName, tblProperties.Street, tblProperties.Unit, tblProperties.City, tblRent.AmountPaid, tblRent.PaymentDate,
tblTenant.Telephone
FROM ((tblProperties INNER JOIN
tblRent ON tblProperties.PropertyID = tblRent.PropertyID) INNER JOIN
tblTenant ON tblProperties.PropertyID = tblTenant.PropertyID)
and here is where i use it in code:
Public Sub getRent()
propView.DataSource = TblPropertiesTableAdapter.GetAllRentReceipts()
propView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)
propView.ReadOnly = True
End Sub
propView is a DataGridView that does not have a DataSource selected at load
I'm assuming that you're using Windows forms and a DataGridView with AutoGenerateColumns turned on.
If you add you own columns only the ones that you select will appear:
propView.AutoGenerateColumns = false
For Each //of the columns that you want
dim column as DataGridViewColumn = New DataGridViewColumn()
column.DataPropertyName = "DB field name"
column.HeaderText = "column title"
propView.Columns.Add( column )
Next
If you build the pages using tags, you'll want the following code in the page...
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1">
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:MY_ConnectionString %>"
SelectCommand="SELECT tblRent.PaymentID, tblTenant.TenantName, tblProperties.Street, tblProperties.Unit, tblProperties.City, tblRent.AmountPaid, tblRent.PaymentDate, tblTenant.TelephoneFROM ((tblProperties INNER JOIN tblRent ON tblProperties.PropertyID = tblRent.PropertyID) INNER JOIN tblTenant ON tblProperties.PropertyID = tblTenant.PropertyID)"></asp:SqlDataSource>
If alternatively you want to use code for the data layer, you could use something along the lines of the following...
Public Class DataLayer
Public Function GetData(ByVal query As String, ByVal params As System.Data.Common.DbParameter()) As System.Data.DataTable
Dim dt As New System.Data.DataTable
Dim constr As String = System.Configuration.ConfigurationManager.ConnectionStrings("constr").ConnectionString()
Using cnObject As New System.Data.SqlClient.SqlConnection(constr)
Using cmd As New System.Data.SqlClient.SqlCommand(query, cnObject)
If Not params Is Nothing Then
For Each param In params
cmd.Parameters.Add(param)
Next
End If
Using da As New System.Data.SqlClient.SqlDataAdapter(cmd)
da.Fill(dt)
Return dt
End Using
End Using
End Using
End Function
End Class
If you are using OLEDB connection, this function can be changed as follows (meaning you only have to change one function to update every use of it in the application - nice)
Public Function GetDataOLE(ByVal query As String, ByVal params As System.Data.Common.DbParameter()) As System.Data.DataTable
Dim dt As New System.Data.DataTable
Dim constr As String = System.Configuration.ConfigurationManager.ConnectionStrings("constr").ConnectionString()
Using cnObject As New System.Data.OleDb.OleDbConnection(constr)
Using cmd As New System.Data.OleDb.OleDbCommand(query, cnObject)
If Not params Is Nothing Then
For Each param In params
cmd.Parameters.Add(param)
Next
End If
Using da As New System.Data.OleDb.OleDbDataAdapter(cmd)
da.Fill(dt)
Return dt
End Using
End Using
End Using
End Function
This function works is a generic data layer that will take in any SQL Command and output the data in a DataTable, which can simply be bound to a grid view or similar. You can check that the "query" is only selecting the columns you want but debugging the code and checking the SQL command to your database.
I would build it into a class so that any page could access it to load data into a data table.
Your code would become
Public Sub getRent()
Dim dataLayer As New DataLayer()
Dim sqlText As String = "<insert your query text here>"
propView.DataSource = dataLayer.getData(sqlText, Nothing)
propView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)
propView.ReadOnly = True
End Sub