Safest way to handle null database items in VB.net - database

For an object such as a DataGridView item or a data set item is the .tostring method safe to use against possible DBnull's?
The application is a mysqlconnector fed DB application which pretty much uses standard query's, but I do come across DBNull quite a bit. Keeping coding efficiency in mind, is the following safe?
Module DataCheck
Public Function SafeDataSTR(DBItem As Object) As String
If Not (IsDBNull(DBItem)) Or Not (IsNothing(DBItem)) Then
Return DBItem.ToString
Else
Return ""
End If
End Function
End Module
'Elsewhere in the galaxy....'
With tempDS.Rows.Item(0) 'tempDS is a standard dataset'
Textbox1.Text = SafeDataSTR(.Item("SupplierDetails")) 'Not necessarily a text box, just an example'
The original solution was:
If Not IsDBNull(.Item("JobDescription")) Then _
jobinfo.Job_Description = .Item("JobDescription")
Which has worked in the past but is there a better safer way to protect yourself from these?
EDIT: Sorry, would DataRow.item("Column").tostring be just as safe?
EDIT: Final Version:
Public Function SafeData_Rowfeed(row As DataRow, ItemName As String) As String
Try
If Not (IsDBNull(row.Item(ItemName))) Then
Return row.Item(ItemName).ToString
ElseIf IsNothing(ItemName) Then
Throw New IndexOutOfRangeException("Supplied Column " & ItemName & "Not found or is Nothing")
Else
Return ""
End If
Catch ex As System.ArgumentException
Console.WriteLine(ex.Message)
Return "Column Does Not Exist"
End Try
End Function

You could 'simplify' it a bit to
Public Function SafeDataSTR(DBItem As Object) As String
Return If(IsDBNull(DBItem), "", If(DBItem.ToString, ""))
End Function
If(DBItem.ToString, "") checks if DBItem.ToString is Nothing.
https://msdn.microsoft.com/en-us/library/bb513985.aspx
Your use of it makes it not the safest method, because the item "SupplierDetails" might not exist.

would DataRow.item("Column").tostring
No it wouldn't as if DataRow.item("Column") is null then calling ToString will cause a null reference exception.
What you have is the safest way of doing this.
In C# 6 and VB 14 there's the ?. syntax, but that basically compiles to the same thing you have, though it will take up one less line of code:
stringValue = DataRow.item("Column")?.ToString
Though this will always set stringValue, so if you want it to retain its current value when the column is null your existing code is still the best way to do this.

Related

How Can I Filter Filtered Data in DataGridView

I'm Having a Problem in filtering Data in Data Grid View, My code works if I use 1 search filter but if I use 2 search filter it's not, first I need to filter it by Courts then the other one is by venue or location
Please give me any idea on how can I make this code works, thank you
My Code:
Private Sub Searchbtn_Click(sender As Object, e As EventArgs) Handles Searchbtn.Click
'Search Code
If Me.Court_AgencyComboBox.Text = "" Then
MessageBox.Show("No Item to be Search", "IBP Legal Aid Case Management System - Legal Aid Case File - Search", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End If
If Not String.IsNullOrEmpty(Me.Court_AgencyComboBox.Text) Then
Me.TblLegalAidCaseFileBindingSource.Filter = String.Format("[Court/Agency] like '%{0}%'", Me.Court_AgencyComboBox.Text)
ElseIf Not String.IsNullOrEmpty(Me.Court_AgencyComboBox.Text) And Not String.IsNullOrEmpty(Me.VenueComboBox.Text) Then
Me.TblLegalAidCaseFileBindingSource.Filter = String.Format("[Court/Agency] like '%{0}%' and Venue like '%{0}%'", Me.Court_AgencyComboBox.Text, Me.VenueComboBox.Text)
Else
RefreshData()
Return
End If
End Sub
The way if-else statements work is that it will execute the first one that meets the condition. In your 1-filter case, it will fulfill this condition If Not String.IsNullOrEmpty(Me.Court_AgencyComboBox.Text) and thus execute that line. However, in your 2-filter case, it will check the first condition If Not String.IsNullOrEmpty(Me.Court_AgencyComboBox.Text) and execute that line too, since the condition is actually fulfilled.
An easy way to solve your problem directly is to swap the conditions. Starting with the condition that is the hardest to fulfill. Which will look like this (I nested your conditions to make it cleaner):
(Code before...)
If Not String.IsNullOrEmpty(Me.Court_AgencyComboBox.Text) Then
If Not String.IsNullOrEmpty(Me.VenueComboBox.Text) Then
Me.TblLegalAidCaseFileBindingSource.Filter = String.Format("[Court/Agency] like '%{0}%' and Venue like '%{1}%'", Me.Court_AgencyComboBox.Text, Me.VenueComboBox.Text)
Else
Me.TblLegalAidCaseFileBindingSource.Filter = String.Format("[Court/Agency] like '%{0}%'", Me.Court_AgencyComboBox.Text)
Else (Code after...)

String array not accepting a string

I'm trying to make a simple login program, but I'm having troubles with assigning a value to my two arrays "User()" and "Pass()". I have the following code on a form titled "frmCreate". This is the form I will be using to create the accounts.
Public Class frmCreate
Dim passs() As String
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnCreate.Click
If Not (txtUser.Text = "") And Not (txtPass.Text = "") Then
userCount = userCount + 1
User(userCount) = txtUser.Text
Pass(userCount) = txtPass.Text
Else
MsgBox("Please enter a username or password")
End If
End Sub
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
passs(0) = "hi"
End Sub
End Class
The issue I'm getting is as follows:
Error in array
The txtPass and txtUser are both text boxes, which can be edited by the user.
Any help would be much appreciated! (Also, I tried mucking around with the variables and all, the strings after the = sign aren't the problem, and when I set the "userCount" inside the brackets to "0" for example, it still returned the same error)
EDIT Added code as text, rather then image (image still there). Note the extra few lines at the end where I set a new array which I named passs() to "hi". The dim is also further up. If I am declaring my variables incorrectly, please let me know.
EDIT2 Ok, I changed my declaration of "User()" and "Pass()" to = {}. Now my problem is that I'm getting the error that the value is out of the bounds of the array. I understand that this happens when you try to call on a non existent value which is outside the arrays boundaries, but the array I set has no boundaries, and I'm just trying to give it a value, not call on one.
EDIT3 Ugh... Ok tweaked a bit, I've found that if I add an unused value to "User()" then it is able to replace it. So I can get the program to replace already existent values in arrays, but I can not get it to create new values in arrays.
It would appear your User variable is NULL. I presume this is intended to be a list of strings or something similar?
You should check the place you are initializing this variable to make sure it is being created...
You could add an
If User Is Nothing
line at the start of the function to check this, and if the list is null at this point create it.
I have discovered what it is I was doing wrong. See, I thought when I declared a variable with empty parenthesis, it created a dynamic variable. This is obviously not the case. Since setting the size of my variable to the ludicrous size of 50,000, my program now works. Thanks to all who tried to help, and sorry for asking the wrong thing :/
Your problem here is that you only defined the variable array. You never reserved a spot for the array values in memory. Therefore your variable has a value of Nothing.
Before assigning the first item, you must assign room for it...
'We say we want an array
Dim passs() As String
'We ask the memory to reserve six spots for our array
passs = New String(5) {}
'We assign the first spot to the String "hi"
passs(0) = "hi"
However, if you don't know how many items you are going to add in your array, I strongly suggest you to use a List(of T) instead :
Dim passs As New List(of String)
passs.Add("hi")

Visual Basic Referencing .Net Objects In An Array

I have a big list of objects in the Design view of Visual Basic 2010 that I need to change a bunch of properties for, so of course I tried using an array rather than taking 50-60 lines for a repetitive task. But there seems to be an issue referencing to the object and it seems to be just taking the information from it. I know that was a shitty explanation, but maybe you'll understand it when you see it.
Dim objectsToClear As Array = _
{lblDailyRoundTrip, lblDaysWorked, lblFillBoxes, lblMilesPerGallon, lblMonthlyInsurance, _
lblMonthlyMaintenance, lblMonthlyParking, tbDailyRoundTrip, tbDaysWorked, tbMilesPerGallon, _
tbMonthlyInsurance, tbMonthlyMaintenance, tbMonthlyParking}
For i = LBound(objectsToClear) To UBound(objectsToClear)
objectsToClear(i).Text = ""
objectsToClear(i).Visible = False
Next
Try this instead:
Dim objectsToClear As Array = { lblDailyRoundTrip,
lblDaysWorked,
lblFillBoxes,
lblMilesPerGallon,
lblMonthlyInsurance,
lblMonthlyMaintenance,
lblMonthlyParking,
tbDailyRoundTrip,
tbDaysWorked,
tbMilesPerGallon,
tbMonthlyInsurance,
tbMonthlyMaintenance,
tbMonthlyParking }
For Each item In objectsToClear
item.Text = String.Empty
item.Visible = False
Next item
P.S. - you REALLY should have Option Strict On, and you should have strongly typed your array.
Since you seem to be interested in changing only .Text and .Visible properties, then you can just find the control by name, like this:
Dim returnValue As Control()
returnValue = Me.Controls.Find(objectsToClear(i), True)
Note: The True argument is for whether or not to search all children, which it sounds like you want to do. Read Control.ControlCollection.Find Method documentation for more information.
Now that you have a collection of controls that match the name you specified, loop through the controls in that collection and set the property values, like this:
For Each c As Control In returnValue
c.Text = ""
c.Visible = False
Next

properly dealing with null database values in vb.net

I am looping thorugh a datatable and and printing each row to the console and I keep on getting a dbnull error. I inserted an if statement in my loop to try and catch it, but I can't seem to get it to work. Any ideas?
Thanks!
Do While reader.Read
For i As Integer = 0 To reader.FieldCount - 1
If reader.IsDBNull(i) Then
Console.Write(Nothing)
Else
Console.Write(reader.GetString(i))
End If
Next
Console.WriteLine(Environment.NewLine())
Changing Console.Write(Nothing) to Console.Write("Nothing") might remove one error, and reader.GetString(i) might throw InvalidCastException errors - you should catch this. reader.IsDBNull(i), however, looks correct.
I have never used the reader methods, but Console.Write(Nothing) would likely have issues. Try this:
Do While reader.Read
For i As Integer = 0 To reader.FieldCount - 1
If reader.Item(i) Is DBNull.Value Then
Console.Write("")
Else
Console.Write(CStr(reader.Item(i)))
End If
Next
Console.WriteLine(Environment.NewLine())
Loop
Why not simply change it to
If NOT isdbnull(reader.Item(i)) Then
Console.Write("")
Else
Console.Write(CStr(reader.Item(i)))
End If
That has always worked better for me. I dont know if there is a DBNull vs DBNull.value issue here.

MS Access - open a form taking a field value from a previous form

I have a form in an MS Access database which lists all the landowners consulted with for a new electricity line. At the end of each row is a button which opens another form, showing the details of all consultation, offers made etc.
I am trying to use vb in MS Access to take the contactID and automatically put it in a field in the details form, so that landowner's consultation details will pop up automatically. I am not a vb programmer at all (I have a comp sci degree mostly in Java and I'm currently working as a GIS analyst but it's a small company so I've been asked to get an Access database working).
I want to say
[detailsForm]![contactID] = [landownerlist]![ID]
in a way that vb and access will be happy with. Then I can see if I'm on the right track and if it will actually work! What I have above does not actually work. It won't compile.
From Kaliana
If you wish to open a form to a new record and to set the ID there, you can use Openargs, an argument of Openform:
DoCmd.OpenForm "FormName",,,,acFormAdd,,Me.ID
The opened form would also need some code:
If Me.Openargs<>vbNullstring Then
Me.Id = Me.Openargs
End If
It is also possible to find:
Forms!LandownersList.Recordset.FindFirst "ID=" & Me.ID
or fill in a value:
Forms!LandownersList!Id = Me.ID
on the form being opened from the calling form.
You may want to look into the code that is behind these buttons. If you are using a docmd.openform you can set the 4th Setting to a where clause on openning the next form.
DoCmd.OpenForm "OpenFormName", acNormal, , "[contactID] = " _
& [detailsForm]![contactID] , acFormEdit, acWindowNormal
This assumes contact ID is numeric and doesn't require any quotes.
Using open args is the generally accepted solution, as alluded to by others. This just falls under the category of "For you edification":) One of the problems with using open args is that unless you are careful with your comments it's easy to forget what they were supposed to mean. Were you passing more than one? Which is which? How did I do it here? How did I do it there etc. For my own money, I standardized to this (below) so I can always pass more than one argument without fear, and when I review my code a year from now, I can still see what's what without a huge hassle:
Option Explicit
'Example use: DoCmd.OpenForm "Example", OpenArgs:="Some Filter|True"
Public Enum eForm1Args
eFilter = 0
eIsSpecial = 1
End Enum
Private m_strArgs() As String
Public Property Get Args(ByVal eForm1Args As eForm1Args) As String
Args = m_strArgs(eForm1Args)
End Property
Private Sub Form_Open(Cancel As Integer)
m_strArgs = Split(Nz(Me.OpenArgs, vbNullString), "|")
If LenB(Me.Args(eFilter)) Then Me.Filter = Me.Args(eFilter)
End Sub
Private Sub Command1_Click()
If LCase$(Me.Args(eIsSpecial)) = "true" Then
'Do something special
End If
End Sub
As previously posted OpenArgs is great for this. One trick I have learned is that it is easy to pass in multiple parameters if required as a delimited string (comma for example), the target form can then access these values using the Split() function thus:
StringArrayVariable()= Split(me.OpenArgs,",")
Me.textbox= StringArrayVariable(0)
Me.textbox1= StringArrayVariable(1)
etc.
This is air code so check out the helpfile for Split().
It is also possible to pass objects in OpenArgs as well, it requires some manual memory pointer manipulation and I don't have the code to hand but I'm sure a Google search will find some examples. This technique can cause some random crashes though. Be Warned!

Resources