Is it possible to change the default decimal separator in float.ToString()? - vb.net

I need to send data in string format to mysql. By default vb.net interprets 0.5 as 0,5 which MySql won't accept. I know I could write floatval.tostring.replace(",", ".") to make it fit but I was wondering if it was possible to make it more comfortable so that an implicit conversion from float to string would produce a dot instead of a comma?
EDIT: per request, current code
Public Sub InsertInto(Values As IEnumerable(Of String))
Dim ValStr As String = ""
For Each V In Values
ValStr &= "'" & V & "',"
Next
Dim Command = New MySqlCommand("INSERT INTO " & Table & " VALUES (" & ValStr.Substring(0, ValStr.Length - 1) & ");", Connection)
Command.ExecuteNonQuery()
End Sub
this method is a part of a mysql connection wrapper and the properties "Connection" and "Table" are preassigned.
My test code calls the function as follows:
dimdum.InsertInto({"DEFAULT", (0.5).ToString.Replace(",", "."), "here is text"})
the test table columns are auto iterating int as primary key, a float and a varchar

As I have saind in my comment above, I am afraid that you need to revise a lot of your code. As is you have a lot of problems, the worst is the Sql Injection that sooner or later you have to fix, but your try to convert everything in a string has also the drawback that the conversion of decimals, dates and other floating points values give more immediate troubles than the Sql Injection one.
There is only one way to get out and it is the use of parameterized queries. More code to write but after a while it is very straightforward.
So for example you should rewrite your code to something like this
Public Sub InsertInto(sqlText As String, Values As List(Of MySqlParameter))
Using Connection = New MySqlConnection(... connectionstring here (or a global variable ....)
Using Command = New MySqlCommand(sqlText, Connection)
Connection.Open()
If Values IsNot Nothing Then
Command.Parameters.AddRange(values.ToArray)
End If
Command.ExecuteNonQuery()
End Using
End Using
End Sub
and call it with this
Dim decValue As Decimal = 0.5
Dim strValue As String = "Test"
Dim dateValue As DateTime = DateTime.Today
Dim parameters = New List(Of MySqlParameter)()
parameters.Add(New MySqlParameter() With { .ParameterName = "#p1",
.DbType = MySqlDbType.Decimal,
.Value = decValue})
parameters.Add(New MySqlParameter() With {.ParameterName = "#p2",
.DbType = MySqlDbType.String,
.Value = strValue})
parameters.Add(New MySqlParameter() With {.ParameterName = "#p3",
.DbType = MySqlDbType.Date,
.Value = dateValue})
InsertInto("INSERT INTO youTable VALUES(#p1, #p2, #p3)", parameters)
Note that now InserInto is just a simple routine that receives the command text and the parameters expected by the text, add them to the command, opens the connection, executes everything and exits closing the connection.
Note also that, with a parameterized queries, your sql command is totally void of the mess caused by single quotes for strings, formatting rules for dates and the handling of the decimal point is nowhere in sight
(A side note. This INSERT INTO text suppose that your table has exactly three fields and you supply the values for all of them, if you want to insert only a subset of fields then you need to pass them to the method as a third parameter )

Specify CultureInfo:
Dim n As Single
Dim s As String
n = Math.PI
s = n.ToString("F2", New System.Globalization.CultureInfo("en-US"))
s will be "3.14", even if your computer is set for a different format.

Related

vb.net option strict on convert string to date

I am trying to convert a string from a database to a Date type with this format "yyyy-M-d"
The string is stored in this format "yyyy-M-d"
So I can execute this code with the Date variables in this format "yyyy-M-d"
Because Option Strict is ON Visual Studio 2019 ver 16.7.5 is UN-happy
If gvTorF = "False" And varToday > varFTue Then
First I am not sure it is necessary but the posts I read about comparing Dates makes this suggestion
Here are my variables
Dim varToday As Date
Dim varFTue As Date
Dim varStr As String
Next I click a Button to get the data from the Database With this code below
Public Sub GetDateInfo()
Using conn As New SQLiteConnection($"Data Source = '{gv_dbName}';Version=3;")
conn.Open()
Using cmd As SQLiteCommand = New SQLiteCommand($"SELECT * FROM DateInfoTable WHERE DID = '1'", conn)
Using rdr As SQLite.SQLiteDataReader = cmd.ExecuteReader
While rdr.Read()
varTorF = rdr("ditORf").ToString
'varFTue = CDate(rdr("diTESTdate")) 'shows as 10/26/2021
'varFTue = Date.ParseExact(varStr, "yyyy-M-d", provider As IFormatProvider, As Date)
'Tried line of code above this can NOT format correct
varTESTdate = CType(rdr("diTESTdate"), String) 'shows as 2021-10-26
End While
rdr.Close()
End Using
End Using
End Using
End Sub
Other than turning Option Strict OFF or just use the format "M-d-yyyy" to run my test
Where varToday > varFTue which seems to work
The Question is what are my other options to make the conversion from String to Date?
The function below will convert the two Strings varTESTdate & varTodayStr
The varTESTdate is from the database and varTodayStr is created in the function bothDates
Here is the Function and the call made behind a Button Click event
bothDates(varTESTdate, varTodayStr)
Public Function bothDates(ByVal varTESTdate As String, ByVal varTodayStr As String) As Object
result1 = Date.ParseExact(varTESTdate, "yyyy-M-d", provider:=Nothing)
Dim dateToday = Date.Today
varTodayStr = dateToday.ToString("yyyy-M-d")
result2 = Date.ParseExact(varTodayStr, "yyyy-M-d", provider:=Nothing)
Return (result1, result2)
End Function
You appear to have the conversion in your code already
Dim d = DateTime.ParseExact("2026-10-26", "yyyy-M-d", Nothing) 'or provide a culture instead of Nothing..
Though I'm not sure what the trailing "As IFormatProvider, As Date" is there for
'varFTue = Date.ParseExact(varStr, "yyyy-M-d", provider As IFormatProvider, As Date)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is a syntax error in this context in vb, and looks like a remnant artifact of a conversion from C# where we use "as X" to perform casts. Don't assume that converters get all code perfect all the time; you nearly always have to fix up their output, especially if pasting in only parts of a program where they can't see all the declared variables (your code appears to not contain provider as a variable)

How can i resolve ExecucuteNonQuery throwing exception Incorrect syntex near '?'

Dim StrSql = "update student set id=?"
Updated (StrSql,15)
Public Function Updated (ByVal strSql As String, ByVal ParamArray Parameters As String ())
For Each x In Parameters
cmd.Parameters.AddWithValue("?",x)
Next
cmd.ExecuteNonQuery()
End Function
You didn't leave us much to go on; as jmcilhinney points out, you need to add more detail to future questions. For example in this one you have code there that doesn't compile at all, doesnt mention the types of any variable, you don't give the name of the database...
...I'm fairly sure that "Incorrect syntax near" is a SQL Server thing, in which case you need to remember that it (re)uses named parameters, unlike e.g. Access which uses positional ones:
SQL Server:
strSql = "SELECT * FROM person WHERE firstname = #name OR lastname = #name"
...Parameters.AddWithValue("#name", "Lee")
Access:
strSql = "SELECT * FROM person WHERE firstname = ? OR lastname = ?"
...Parameters.AddWithValue("anythingdoesntmatterwillbeignored", "Lee")
...Parameters.AddWithValue("anythingdoesntmatterwillbeignoredalso", "Lee")
This does mean your function will need to get a bit more intelligent; perhaps pass a ParamArray of KeyValuePair(Of String, Object)
Or perhaps you should stop doing this way right now, and switch to using Dapper. Dapper takes your query, applies your parameters and returns you objects if you ask for them:
Using connection as New SqlConnection(...)
Dim p as List(Of Person) = Await connection.QueryAsync(Of Person)( _
"SELECT * FROM person WHERE name = #name", _
New With { .name = "John" } _
)
' use your list of Person objects
End Using
Yep, all that adding parameters BS, and executing the reader, and converting the results to a Person.. Dapper does it all. Nonquery are done like connection.ExecuteAsync("UPDATE person SET name=#n, age=#a WHERE id=#id", New With{ .n="john", .a=27, .id=123 })
http://dapper-tutorial.net
Please turn on Option Strict. This is a 2 part process. First for the current project - In Solution Explorer double click My Project. Choose Compile on the left. In the Option Strict drop-down select ON. Second for future projects - Go to the Tools Menu -> Options -> Projects and Solutions -> VB Defaults. In the Option Strict drop-down select ON. This will save you from bugs at runtime.
Updated(StrSql, 15)
Your Updated Function calls for a String array. 15 is not a string array.
Functions need a datatype for the return.
cmd.Parameters.AddWithValue("?", X)
cmd is not declared.
You can't possible get the error you mention with the above code. It will not even compile, let alone run and produce an error.
It is not very helpful to write a Function that is trying to be generic but is actually very limited.
Let us start with your Update statement.
Dim StrSql = "update student set id=?"
The statement you provided will update every id in the student table to 15. Is that what you intended to do? ID fields are rarely changed. They are meant to uniquely identify a record. Often, they are auto-number fields. An Update command would use an ID field to identify which record to update.
Don't use .AddWithValue. See http://www.dbdelta.com/addwithvalue-is-evil/
and
https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
and another one:
https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications
Here is another
https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html
Since you didn't tell us what database you are using I guessed it was Access because of the question mark. If it is another database change the connection, command and dbType types.
Using...End Using block ensures you connection and command are closed and disposed even if there is an error.
Private ConStr As String = "Your Connection String"
Public Function Updated(StudentNickname As String, StudentID As Integer) As Integer
Dim RetVal As Integer
Using cn As New OleDbConnection(ConStr),
cmd As New OleDbCommand("Update student set NickName = #NickName Where StudentID = #ID", cn)
cmd.Parameters.Add("#NickName", OleDbType.VarChar, 100).Value = StudentNickname
cmd.Parameters.Add("#ID", OleDbType.Integer).Value = StudentID
cn.Open()
RetVal = cmd.ExecuteNonQuery
End Using
Return RetVal
End Function
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim RowsUpdated = Updated("Jim", 15)
Dim message As String
If RowsUpdated = 1 Then
message = "Success"
Else
message = "Failure"
End If
MessageBox.Show(message)
End Sub
This code keeps your database code separated from user interface code.

vb.net Interpolated Strings

I was chastised by a professional developer with a lot of years of experience for Hard Coding my DB name
OK I get it we sometimes carry our bad codding habits with us till we learn the correct way to code
I have finally learned to use Interpolated Strings (personal view they are not pretty)
My Question involves the two Sub's posted below GetDB runs first then HowMany is called from GetDB
Sorry for stating the obvious my reason is I think that NewWord.db gets declared in GetDB and works in HowMany without the same construction Just a Wild Guess
Notice NO $ or quotation used in HowMany
Both Sub's produce desired results
The question is Why don't both statements need to be constructed the same?
Public Sub HowMany()
'Dim dbName As String = "NewWord.db"
Dim conn As New SQLiteConnection("Data Source ='{NewWord.db}';Version=3;")
tot = dgvOne.RowCount ' - 1
tbMessage.Text = "DGV has " & tot.ToString & " Rows"
End Sub
Private Sub GetDB()
Dim str2 As String
Dim s1 As Integer
'Dim dbName As String = "NewWord.db"
Using conn As New SQLiteConnection($"Data Source = '{"NewWord.db"}' ;Version=3;")
conn.Open()
That second method is a ridiculous and pointless use of string interpolation. What could possibly be the point of inserting a literal String into a literal String? The whole point is that you can insert values determined at run time. That second code is equivalent to using:
"Data Source = '" & "NewWord.db" & "' ;Version=3;"
What's the point of that? The idea is that you retrieve your database name from somewhere at run time, e.g. your config file, and then insert that into the template String, e.g.
Dim dbName = GetDbNameFromExternalFile()
Using conn As New SQLiteConnection($"Data Source = '{dbName}' ;Version=3;")
Now the user can edit that external file to change the database name after deploying the application. How could they change the name in your code?
To be clear, string interpolation is just native language support for the String.Format method. You can see that if you make a mistake that generates an exception and the that exception will refer to the String.Format method. In turn, String.Format is a way to make code that multiple values into a long template easier to read than if multiple concatenation operators were used.
Having lots of quotes and ampersands makes code hard to read and error-prone. I've lost count of the number of times people miss a single quote or a space or the like in a String because they couldn't read there messy code. Personally, I'll rarely use two concatenation operators in the same expression and never three. I'll do this:
Dim str = "some text" & someVar
but I'll rarely do this:
Dim str = "some text" & someVar & "some more text"
and I'll never do this:
Dim str = "some text" & someVar & "some more text" & someOtherVar
Before string interpolation, I would use String.Format:
Dim str = String.Format("some text{0}some more text{1}", someVar, someOtherVar)
Nowadays, I'll generally use string interpolation:
Dim str = $"some text{someVar}some more text{someOtherVar}"
Where I may still use String.Format over string interpolation is if one value is getting inserted in multiple places and/or where the text template and/or the expressions are long so that I can break the whole thing over multiple lines, e.g.
Dim str = String.Format("some text{0}some more text{1}yet more text{0}",
someVar,
someOtherVar)
I have no idea what NewWord.db is so I made a class to represent it.
Public Class NewWord
Public Shared Property db As String = "The db Name"
End Class
HowMany is not a very good name for your sub. Try to use more descriptive names.
The first sub doesn't even use the connection. The connection string in that code is a literal string. It will not consider NewWord.db as a variable. You will not notice this because you never attempt to open the connection. In my version you check the connection string with a Debug.Print.
I changed the last line to use and interpolated string. It is not necessary to call .ToString on tot.
Private Sub DisplayGridCount()
Dim conn As New SQLiteConnection("Data Source ='{NewWord.db}';Version=3;")
Debug.Print(conn.ConnectionString)
Dim tot = DataGridView1.RowCount
TextBox1.Text = $"DGV has {tot} Rows"
End Sub
The second snippet starts off with 2 unused variables. I deleted them. Again, the Debug.Print to show the difference in the 2 strings.
Private Sub TestConnection()
Using conn As New SQLiteConnection($"Data Source = '{NewWord.db}' ;Version=3;")
Debug.Print(conn.ConnectionString)
'conn.Open()
End Using
End Sub
As to where to store connection strings see https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/protecting-connection-information and Where to store Connection String

Converting Empty String to NULL Double

I have spent much of the day trying to find an answer for this one. I figured it would be easy but nothing is specific to what I am trying to do. So I hope someone can help.
I am bringing values over from one system to another. I have a few fields that come over as strings but they need to go into the new system as DOUBLE. The problem occurs when there are empty strings ("") and it is trying to store this as double. I have tried EVERYTHING.
dbnull.value
Double.TryParse
CDBL()
Double?
VAL()
etc...cannot get this to work and I am not sure why.
so here is the code:
Dim specvertclr As String = dt23.Rows(0).ItemArray.GetValue(38).ToString()
then when I insert this into my database I get the error because the field type is NUMERIC and I am trying to insert ""
I did have this working:
Dim specvertclr As String
If dt23.Rows(0).ItemArray.GetValue(38).ToString() = "" Then
specvertclr = CStr(0)
Else
specvertclr = dt23.Rows(0).ItemArray.GetValue(38).ToString()
End If
But the problem with this is it inserts a 0 value and 0 is not the same as NULL. I want the NUMERIC field in my destination database (SQLCE) to be EMPTY when the string is empty from the source database.
Any help?
This is what I tried:
Dim specvertclr As Nullable(Of Double) = CType(dt23.Rows(0).ItemArray.GetValue(38).ToString(), Double?)
and then my insert is basic and the program throws an error before it even gets here. I know this part is correct.
Dim cmd2 As SqlCeCommand = conn.CreateCommand()
cmd2.CommandText = "Insert into [Attr_Bridge] ([VERTCLR]) VALUES (?)"
With cmd2.Parameters
.AddWithValue("P1", specvertclr)
end with
You need to check the content of your string before adding it to the database
Dim specvertclr = dt23.Rows(0).ItemArray.GetValue(38).ToString()
....
Dim cmd2 As SqlCeCommand = conn.CreateCommand()
cmd2.CommandText = "Insert into [Attr_Bridge] ([VERTCLR]) VALUES (#P1)"
With cmd2.Parameters
.Add("#P1", SqlDbType.Float).Value = If(String.IsNullOrEmpty(specvertclr), DBNull.Value, CType(specvertclr, Object))
This turned out to be the answer .... Thank You Arminius for your linked article that lead me to right answer ... Thank you Steve for your time and help!
Dim specvertclr As String = dt23.Rows(0).ItemArray.GetValue(38).ToString()
Dim oerrorspec As Object = System.DBNull.Value
If specvertclr <> Nothing Then oerrorspec = specvertclr
and then in the parameters section I used this
.Add(New SqlCeParameter("#P41", oerrorspec))
I came across this question because I had the same issue. I was creating an app and one of the inputs was optional and I didn't want users to worry about putting zero so they don't receive an error. So my question was how to convert "" string to double? I came up with the below:
Dim Nontaxable As Double
If txtNontaxable.Text IsNot "" Then
Nontaxable = CDbl(txtNontaxable.Text)
Else
txtNontaxable.Text = 0
End If
if the string isn't blank, it will be converted fine, if its blank, it will be replaced with zero, and then it will be converted fine. Hope this helps anyone had the same issue.

String.Format for Integer is Incorrect in VB.Net

This should not happen, so I must be missing something simple.
In the below VB function, I am trying to generate a list of part numbers to display on the screen using this format statement:
ticket = String.Format("{0:000}-{1:00000}-{2:00}", storeNumber, order, release)
With that, ticket should have the format xxx-yyyyy-zz so that the ticket is human readable and the other parts of my application can parse this data.
Public Shared Function GetShipTickets(storeNumber As Integer, auditor As String, startDate As DateTime) As ShipTickets
Dim list As New ShipTickets(auditor)
list.Display = String.Format("Since {0:MMMM d}.", startDate)
Const sqlCmd As String =
"SELECT TICKET_STORE, TICKET_ORDER, TICKET_RELEASE " &
"FROM TBLRELHDR " &
"WHERE TICKET_STORE=#TICKET_STORE AND STATUS='C' AND #CREATE_DATE<=CREATE_DATE " &
"ORDER BY TICKET_ORDER, TICKET_RELEASE, CREATE_DATE; "
Dim table As New DataTable()
Using cmd As New DB2Command(sqlCmd, Db2CusDta)
cmd.Parameters.Add("TICKET_STORE", DB2Type.SmallInt).Value = storeNumber
cmd.Parameters.Add("CREATE_DATE", DB2Type.Char, 8).Value = String.Format("{0:yyyyMMdd}", startDate)
table.Load(cmd.ExecuteReader())
End Using
If 0 < table.Rows.Count Then
For Each row As DataRow In table.Rows
Dim order As String = String.Format("{0}", row("TICKET_ORDER")).Trim().ToUpper()
Dim release As String = String.Format("{0}", row("TICKET_RELEASE")).Trim().ToUpper()
Dim ticket As String = String.Format("{0:000}-{1:00000}-{2:00}", storeNumber, order, release)
list.Add(ticket)
Next
End If
list.Sort()
Return list
End Function
It is not working, though.
Also, when I view my data on the screen, it is not displaying correctly either:
What is going on?
VB is not my strongest programming language. Either there is some nuance of VB that I am unaware of or the compiler is messing up.
Using Visual Studio 2012
The format "{2:00}" works on integers, not strings. It won't automatically convert a string consisting of digits into an integer. Manually convert the strings to integers:
Dim ticket As String = String.Format("{0:000}-{1:00000}-{2:00}",
CInt(storeNumber),
CInt(order),
CInt(release))