Home > database >  The conversion from String "@StartingDate" to type'Integer' is invalid
The conversion from String "@StartingDate" to type'Integer' is invalid

Time:05-12

I've googled that error(in title) but I can't seem to get it to help me. My goal is to insert all the data value into database table. My query code;

Try
For Each value As Type.Structures.R_Warehouse In dataList
Dim sql As String = String.Empty
sql &= "DELETE FROM" & Common.Constant.TBL_R_WAREHOUSE & ""
sql &= "WHERE InvDate = HMCS.dbo.f_GetInvDate()"
sql &= "AND InvID = @InvID AND InvDate = HMCS.dbo.f_GetInvDate()"    

sql &= "INSERT INTO" & Common.Constant.TBL_H_WHSTRANS & ""
sql &= " SELECT (SELECT dbo.f_GetNewTransID(substring(convert(varchar,getdate(),112),3,6)) as ID)"
sql &= ",@InvID "
sql &= ",@ItemID "
sql &= ",@Qty "   
sql &= ",@StartingDate "
sql &= ",@SANote "
sql &= ",convert(varchar,GETDATE(),120)"
sql &= ",'" & Setting.SettingHelper.HostName & "'"

Using cmd As New SqlCommand(sql.ToString, cn, tran)
With cmd
.Parameters.Add("@InvID", SqlDbType.VarChar).Value = value.InvID
.Parameters.Add("@ItemID", SqlDbType.Int).Value = value.ItemID
.Parameters.Add("@Qty", SqlDbType.Decimal, 4).Value = value.Qty
    
If IsDBNull("@StartingDate") = False Then
.Parameters.Add("@StartingDate", SqlDbType.Date, 8).Value = value.StartingDate
End If
    
.Parameters.Add("@SANote", SqlDbType.VarChar).Value = value.SANote
.ExecuteNonQuery()
End With

But it always gives me an error info

The conversion from String "@StartingDate" to type'Integer' is invalid.

Any help would be greatly appreciated.

CodePudding user response:

Even though my question in the comments wasn't answered, I think I can glean enough information from what was posted to work out what's going on and what should be done. It seems that we're just not going to get a clear explanation so a best guess is all I can provide.

It appears that the point of the If statement that is causing the problem is to insert NULL into the database if value.StartingDate is not set and insert the value that is set otherwise. As it stands, it appears that value.StartingDate is type Date. Note that Date and DateTime are the same type, just as Integer and Int32 are the same type. In that case, it will ALWAYS have a value. Just as an Integer variable will be zero by default, so a Date variable will be #1/01/0001 00:00:00# by default. If you insist on using a Date property there then you need to look for that default value and use DBNull.Value if you find it. That could be done with an If block:

If value.StartingDate = Nothing Then
    .Parameters.Add("@StartingDate", SqlDbType.Date).Value = DBNull.Value
Else
    .Parameters.Add("@StartingDate", SqlDbType.Date).Value = value.StartingDate
End If

It would be better to use the If operator though:

.Parameters.Add("@StartingDate", SqlDbType.Date).Value = If(value.StartingDate = Nothing,
                                                            CObj(DBNull.Value),
                                                            value.StartingDate)

Note that I have used Nothing for comparison there because Nothing is always the default for value type variables. What that actually corresponds to depends on the type. For numeric types, it corresponds to zero, while it corresponds to Date.MinValue for the Date type.

That will work, but it's not the best solution.

A better solution would be to declare the property type Date?, i.e. Nullable(Of Date) rather than Date. If you want a variable to be able to contain no value then you should use a nullable type. That way, instead of the property containing Date.MinValue by default, it will genuinely contain Nothing, i.e. no value. It will only contain an actual Date value if you assign one. You can then do this:

.Parameters.Add("@StartingDate", SqlDbType.Date).Value = If(value.StartingDate.HasValue,
                                                            value.StartingDate.Value,
                                                            CObj(DBNull.Value))

Note that CObj is used because the If operator requires both potential return values to be the same type or one type inherit the other. In this case, neither DBNull nor Date inherit the other, so at least one must be cast as Object. Everything inherits Object, so any other return value will be valid. This means that the return type of If is Object, but that's fine because it is being assigned the Value property of a parameter, which is also of type Object.

CodePudding user response:

There are quite a few things in the code in the question that I would do differently - please don't take my code as being the paragon of VB.NET, but I think it is something closer to what you intend to do.

I had to guess at what you were trying to do with the SQL transaction.

Adding a New SqlParameter With {...} might seem tedious, but look at how easy it is to know what each parameter is for. Easy-to-read code pays for itself in ease of getting it right and maintenance.

If you are using a version of Visual Studio that doesn't allow multi-line strings then you really need to update it. To one that also uses interpolated strings ;)

Try to put spaces after commas to make the code easier to read.

My attempt at getting the code in the question to be what you need is:

Imports System.Data.SqlClient
Imports System.Data.SqlTypes

' This is only for the example on SO.
Namespace Type.Structures
    Class R_Warehouse
        Property InvID As String
        Property ItemID As Integer
        Property Qty As Decimal
        Property StartingDate As Date?
        Property SANote As String
    End Class
End Namespace

Module Module1

    ' This is only for the example on SO.
    Friend Class Common
        Friend Class Constant
            Friend Shared TBL_R_WAREHOUSE As String
            Friend Shared TBL_H_WHSTRANS As String
        End Class
    End Class

    ' This is only for the example on SO.
    Friend Class Setting
        Friend Class SettingHelper
            Friend Shared Property HostName As String
        End Class
    End Class

    Sub X() ' I had no better name for this method.
        Dim dataList As New List(Of Type.Structures.R_Warehouse) ' Only for this SO code.
        Dim connStr = "your connection string goes here" ' Only for this SO code.

        Dim sqlDelete = $"DELETE FROM [{Common.Constant.TBL_R_WAREHOUSE}] WHERE InvDate = HMCS.dbo.f_GetInvDate() AND InvID = @InvID"

        'TODO: Put the column names in as indicated.
        Dim sqlInsert = $"INSERT INTO [{Common.Constant.TBL_H_WHSTRANS}]
                                 VALUES(put the column names here)
                                 SELECT (SELECT dbo.f_GetNewTransID(SUBSTRING(CONVERT(VARCHAR, GETDATE(), 112), 3, 6)) As ID)
                                               ,@InvID
                                               ,@ItemID
                                               ,@Qty
                                               ,@StartingDate
                                               ,@SANote
                                               ,CONVERT(VARCHAR, GETDATE(), 120)
                                               ,@HostName"

        Using conn As New SqlConnection(connStr)
            conn.Open()

            'TODO: Consider the scope of the transaction - maybe a transaction is needed individually for each item in dataList instead of all of them in one go.
            Dim tran = conn.BeginTransaction("OverallTransaction")

            Try

                For Each rwItem As Type.Structures.R_Warehouse In dataList

                    Using cmd As New SqlCommand(sqlDelete, conn, tran)
                        cmd.Parameters.Add(New SqlParameter With {.ParameterName = "@InvId", .SqlDbType = SqlDbType.VarChar, .Value = rwItem.InvID})
                        cmd.ExecuteNonQuery()

                    End Using

                    Using cmd As New SqlCommand(sqlInsert, conn, tran)
                        'TODO: Set the .Size parameter for the VarChar to match the column in the database.
                        cmd.Parameters.Add(New SqlParameter With {.ParameterName = "@InvID", .SqlDbType = SqlDbType.VarChar, .Value = rwItem.InvID})
                        cmd.Parameters.Add(New SqlParameter With {.ParameterName = "@ItemID", .SqlDbType = SqlDbType.Int, .Value = rwItem.ItemID})
                        'TODO: Set the .Precision and .Scale values to match the column in the database.
                        cmd.Parameters.Add(New SqlParameter With {.ParameterName = "@Qty", .SqlDbType = SqlDbType.Decimal, .Precision = 8, .Scale = 4, .Value = rwItem.Qty})

                        Dim startDateParam = New SqlParameter With {.ParameterName = "@StartingDate", .SqlDbType = SqlDbType.Date}

                        ' The MinValue and MaxValue checks may or may not be needed.
                        If rwItem.StartingDate.HasValue AndAlso
                            rwItem.StartingDate > SqlDateTime.MinValue AndAlso
                            rwItem.StartingDate < SqlDateTime.MaxValue Then
                            startDateParam.Value = rwItem.StartingDate
                        Else
                            startDateParam.Value = DBNull.Value
                        End If

                        cmd.Parameters.Add(startDateParam)

                        'TODO: Set the .Size parameter for the VarChar to match the column in the database.
                        cmd.Parameters.Add(New SqlParameter With {.ParameterName = "@SANote", .SqlDbType = SqlDbType.VarChar, .Value = rwItem.SANote})

                        'TODO: Set the .Size parameter for the VarChar to match the column in the database.
                        cmd.Parameters.Add(New SqlParameter With {.ParameterName = "@HostName", .SqlDbType = SqlDbType.VarChar, .Value = Setting.SettingHelper.HostName})

                        cmd.ExecuteNonQuery()

                    End Using
                Next

                tran.Commit()

            Catch ex As Exception
                tran.Rollback()
                ' Do something useful
            End Try

        End Using

    End Sub

End Module
  • Related