I just begin with Oracle. I read lot of post and ... I don't find where is my mistake
I've a function in package PKG_GETOBJ
FUNCTION GetNewID(sReference IN VARCHAR2) RETURN NUMBER
IS
NewCtpVal NUMBER;
BEGIN
UPDATE TABLE set VALUE = (VALUE + 1) WHERE Field= sReference RETURN VALUE INTO NewCtpVal;
return NewCtpVal;
END;
and here how I try to call it:
Dim con As OracleConnection = GetConnexion()
con.Open()
Dim cmd As New OracleCommand With {.Connection = con}
'PKG_GETOBJ.GETNEWID('ID_OBJECT');'Sample calling in SQL with success
cmd.Parameters.Add(New OracleParameter With {.ParameterName = "sReference", .OracleDbType = OracleDbType.Varchar2, .Value = "ID_OBJECT", .Direction = ParameterDirection.Input})
cmd.Parameters.Add(New OracleParameter With {.ParameterName = "NewCtpVal", .OracleDbType = OracleDbType.Double, .Direction = ParameterDirection.ReturnValue})
cmd.CommandText = "PKG_GETOBJ.GETNEWID"
cmd.CommandType = CommandType.StoredProcedure
cmd.ExecuteNonQuery()
For Each p As OracleParameter In cmd.Parameters
HelperJournal.WriteEntry("PKG_GETOBJ " & p.ParameterName, If(p.Value Is Nothing, "null", p.Value.ToString))'Write in file
Next
con.Close()
con.Dispose()
My problem is NewCtpVal is empty, then I Database I've a number value...
Finnally I found a way...
Public Function GetNewId() As Decimal
Dim retval
Using con As OracleConnection = GetConnexion(),
cmd As New OracleCommand With {.Connection = con}
cmd.CommandText = "PKG_GETOBJ.GETNEWID"
cmd.CommandType = CommandType.StoredProcedure
Dim prm = New OracleParameter("returnvalue", OracleDbType.Decimal)
prm.Direction = ParameterDirection.ReturnValue
cmd.Parameters.Add(prm)
Dim prm1 = New OracleParameter("sReference", OracleDbType.Varchar2)
prm1.Direction = ParameterDirection.Input
prm1.Value = "ID_OBJECT"
cmd.Parameters.Add(prm1)
con.Open()
cmd.ExecuteNonQuery()
retval = cmd.Parameters("returnvalue").Value.ToString
End Using
Return retval
End Function
I use the first "Using" statement below to insert a row to a table called "Archives". This table has a primary key that is an autonum in an Access db. The second Using statement I use to retrieve the value for the autonum field, searching by the parameters that I just entered. While this works perfectly well, it just seems ugly. Is there a way to get the autonum field returned to me after the insert? (BTW - I have deleted some code from between these two statements so if it looks a little strange, that may be why.
Using myConn As New OleDbConnection(strConnectionString),
myInsertCommand As New OleDbCommand("INSERT INTO Archives (ArchUserName, ArchUserDomain, ArchDate, ArchRoot, ArchStatus)
VALUES (#strArchUser, #strArchUserDomain, #dteArchDate, #strArchRoot, #strArchStatus);", myConn)
myInsertCommand.Parameters.Add("#strArchUser", OleDbType.VarChar, 100).Value = strArchUser
myInsertCommand.Parameters.Add("#strArchDomain", OleDbType.VarChar, 100).Value = strArchDomain
myInsertCommand.Parameters.Add("#dteArchDate", OleDbType.Date, 20).Value = dteArchDate
myInsertCommand.Parameters.Add("#strArchRoot", OleDbType.VarChar, 255).Value = strArchRoot
myInsertCommand.Parameters.Add("#strArchStatus", OleDbType.VarChar, 100).Value = strArchStatus
myConn.Open()
myInsertCommand.ExecuteNonQuery()
End Using
Dim sql As String = "SELECT ArchID
FROM Archives
WHERE ArchUserName = #ArchUserName
AND ArchUserDomain = #ArchUserDomain
AND ArchDate = #ArchDate
AND ArchRoot = #ArchRoot"
Using myConn As New OleDbConnection(strConnectionString),
command As New OleDbCommand(sql, myConn)
With command.Parameters
.Add("#ArchUserName", OleDbType.VarChar, 50).Value = strArchUser
.Add("#ArchUserDomain", OleDbType.VarChar, 50).Value = strArchDomain
.Add("#ArchDate", OleDbType.Date).Value = dteArchDate
.Add("#ArchRoot", OleDbType.VarChar, 50).Value = strArchRoot
End With
myConn.Open()
strArchID = "Arch" & CStr(command.ExecuteScalar())
strDirectoryName = "Archive" & CStr(command.ExecuteScalar())
ReturnCode = 0
End Using
Use ##Identity on the same connection immediately after the insert.
Private Function InsertArchiveRetrieveID(strArchUser As String, strArchDomain As String, dteArchDate As Date, strArchRoot As String, strArchStatus As String) As Integer
Dim NewID As Integer
Using myConn As New OleDbConnection(strConnectionString),
myInsertCommand As New OleDbCommand("INSERT INTO Archives (ArchUserName, ArchUserDomain, ArchDate, ArchRoot, ArchStatus)
VALUES (#strArchUser, #strArchUserDomain, #dteArchDate, #strArchRoot, #strArchStatus);", myConn)
With myInsertCommand.Parameters
.Add("#strArchUser", OleDbType.VarChar, 100).Value = strArchUser
.Add("#strArchDomain", OleDbType.VarChar, 100).Value = strArchDomain
.Add("#dteArchDate", OleDbType.Date, 20).Value = dteArchDate
.Add("#strArchRoot", OleDbType.VarChar, 255).Value = strArchRoot
.Add("#strArchStatus", OleDbType.VarChar, 100).Value = strArchStatus
End With
myConn.Open()
myInsertCommand.ExecuteNonQuery()
Using RetrieveNewIDCommand As New OleDbCommand("Select ##Identity From Archives,", myConn)
NewID = CInt(RetrieveNewIDCommand.ExecuteScalar)
End Using
End Using
Return NewID
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim NewID = InsertArchiveRetrieveID(txtUser.Text, txtDomain.Text, DateTimePicker1.Value, txtRoot.Text, txtStatus.Text)
Dim strArchID = "Arch" & CStr(NewID)
Dim strDirectoryName = "Archive" & CStr(NewID)
End Sub
I'm working in Visual Basic to create a forms applications as part of a college project. I've used SQL statements to read from the access database but I'm having some trouble writing to it. I'd like to hazard a guess it's due to the database having relationships between tables.
This is my first go at making something substantial, and vb is not my language of choice. Expect the code to be poor at best. If anyone has links to resources that I could use to improve I'd be immensely grateful.
Exception:
Exception thrown: 'System.Data.OleDb.OleDbException: 'No value given for one or more required parameters.'
Exception location: 'commAddToStaff.ExecuteNonQuery()'
Both try statements are catching exceptions when ran. I've attempted providing data in the parameters rather than using data from a text box, but this hasn't resolved the issue.
Code:
Private Sub btnAddStaffMember_Click(sender As Object, e As EventArgs) Handles btnAddStaffMember.Click
'Dimension tblStaff Parameters
Dim AddEmployeeIDParam As New OleDb.OleDbParameter("#AddEmployeeID", txtAddEmployeeID.Text)
Dim AddForenameParam As New OleDb.OleDbParameter("#AddForename", txtAddForename.Text)
Dim AddSurnameParam As New OleDb.OleDbParameter("#AddSurname", txtAddSurname.Text)
Dim AddDOBParam As New OleDb.OleDbParameter("#AddDOB", txtAddDOB.Text)
Dim AddUserTierParam As New OleDb.OleDbParameter("#AddUserTier", txtAddUserTier.Text)
'Dimension tblContacts Parameters
Dim conContact As New OleDb.OleDbConnection("Provider=Microsoft.......")
Dim commContactCount As New OleDb.OleDbCommand("Select Count(*) FROM tblContacts", conContact)
commContactCount.Connection.Open()
Dim ContactID = commContactCount.ExecuteScalar + 1 'Calculate the contactID of the new record
commContactCount.Connection.Close() 'Close the connection
Dim AddContactIDParam As New OleDb.OleDbParameter("#AddContactID", ContactID)
Dim AddAddressParam As New OleDb.OleDbParameter("#AddAddress", txtAddAddress.Text)
Dim AddPostcodeParam As New OleDb.OleDbParameter("#AddPostcode", txtAddPostcode.Text)
Dim AddEmailParam As New OleDb.OleDbParameter("#AddEmail", txtAddEmail.Text)
Dim AddMobileNoParam As New OleDb.OleDbParameter("#AddMobileNo", txtAddMobileNumber.Text)
Dim conAddToStaff As New OleDb.OleDbConnection("Provider=Microsoft....")
Dim commAddToStaff As New OleDb.OleDbCommand("Insert Into tblStaff (EmployeeID, Forename, Surname, DOB, User_Tier, ContactID) Values (#AddEmployeeID, #AddForename, #AddSurname, #AddDOB, #AddUserTier, #AddContactID)", conAddToStaff)
commAddToStaff.Parameters.Add(AddEmployeeIDParam)
commAddToStaff.Parameters.Add(AddForenameParam)
commAddToStaff.Parameters.Add(AddSurnameParam)
commAddToStaff.Parameters.Add(AddDOBParam)
commAddToStaff.Parameters.Add(AddUserTierParam)
Dim commAddToContact As New OleDb.OleDbCommand("Insert Into tblContacts (ContactID, Address, Postcode, Email, Mobile_Number) Values (#AddContactID, #AddAddress, #AddPostcode, #AddEmail, #AddMobileNo)", conContact)
commAddToContact.Parameters.Add(AddContactIDParam)
commAddToContact.Parameters.Add(AddAddressParam)
commAddToContact.Parameters.Add(AddPostcodeParam)
commAddToContact.Parameters.Add(AddEmailParam)
commAddToContact.Parameters.Add(AddMobileNoParam)
Try
commAddToStaff.Connection.Open() 'Open a connection to the database
commAddToStaff.ExecuteNonQuery() 'Execute the command
commAddToStaff.Connection.Dispose() 'Remove unmanaged resources
commAddToStaff.Connection.Close() 'Close the connection
Catch ex As Exception
MessageBox.Show("Error with staff")
End Try
Try
commAddToContact.Connection.Open() 'Open a connection to the database
commAddToContact.ExecuteNonQuery() 'Execute the command
commAddToContact.Connection.Dispose() 'Remove unmanaged resources
commAddToContact.Connection.Close() 'Close the connection
Catch ex As Exception
MessageBox.Show("Error with contacts")
End Try
MessageBox.Show("Reached")
Me.Hide() 'Close the Current screen
StaffDB_Add_Staff_Security_Question.Show() 'Open the Add Security Question Screen
End Sub
You are inserting six values into six columns here:
Dim commAddToStaff As New OleDb.OleDbCommand("Insert Into tblStaff (EmployeeID, Forename, Surname, DOB, User_Tier, ContactID) Values (#AddEmployeeID, #AddForename, #AddSurname, #AddDOB, #AddUserTier, #AddContactID)", conAddToStaff)
but you only add five parameters to the command here:
commAddToStaff.Parameters.Add(AddEmployeeIDParam)
commAddToStaff.Parameters.Add(AddForenameParam)
commAddToStaff.Parameters.Add(AddSurnameParam)
commAddToStaff.Parameters.Add(AddDOBParam)
commAddToStaff.Parameters.Add(AddUserTierParam)
Where's the parameter for the #AddContactID placeholder in the SQL code?
EDIT:
For the record, here's how I would tend to write code for that sort of task, ignoring the horrible way you're generating the ContactID value:
Using connection As New OleDbConnection("connection string here")
connection.Open()
Dim contactCount As Integer
Using contactCountCommand As New OleDbCommand("SELECT COUNT(*) FROM tblContacts", connection)
contactCount = CInt(contactCountCommand.ExecuteScalar())
End Using
Dim contactId = contactCount + 1
Using staffCommand As New OleDbCommand("INSERT INTO tblStaff (EmployeeID, Forename, Surname, DOB, User_Tier, ContactID) Values (#EmployeeID, #Forename, #Surname, #DOB, #User_Tier, #ContactID)", connection)
With staffCommand.Parameters
.Add("#EmployeeID", OleDbType.VarChar, 50).Value = txtAddEmployeeID.Text
.Add("#Forename", OleDbType.VarChar, 50).Value = txtAddForename.Text
.Add("#Surname", OleDbType.VarChar, 50).Value = txtAddSurname.Text
.Add("#DOB", OleDbType.Date).Value = CDate(txtAddDOB.Text) 'Why isn't this coming from a DateTimePicker?
.Add("#User_Tier", OleDbType.VarChar, 50).Value = txtAddUserTier.Text
.Add("#ContactID", OleDbType.Integer).Value = contactId
End With
staffCommand.ExecuteNonQuery()
End Using
Using contactCommand As New OleDbCommand("INSERT INTO tblContacts (ContactID, Address, Postcode, Email, Mobile_Number) Values (#ContactID, #Address, #Postcode, #Email, #Mobile_Number)", connection)
With contactCommand.Parameters
.Add("#ContactID", OleDbType.Integer).Value = contactId
.Add("#Address", OleDbType.VarChar, 50).Value = txtAddAddress.Text
.Add("#Postcode", OleDbType.VarChar, 50).Value = txtAddPostcode.Text
.Add("#Email", OleDbType.VarChar, 50).Value = txtAddEmail.Text
.Add("#Mobile_Number", OleDbType.VarChar, 50).Value = txtAddMobileNumber.Text
End With
contactCommand.ExecuteNonQuery()
End Using
End Using
It would be easier to see where there are insufficient parameters added by rearranging the code into smaller pieces, where related items are near to each other. Something like:
Imports System.Data.OleDb
Public Class Form1
Dim connStr As String = "Provider=Microsoft......."
Sub AddStaffMemberToDatabase(contactId As Integer)
Dim sql = "INSERT INTO tblStaff (EmployeeID, Forename, Surname, DOB, UserTier, ContactID) VALUES (#AddEmployeeID, #AddForename, #AddSurname, #AddDOB, #AddUserTier, #AddContactID)"
Using conn As New OleDbConnection(connStr),
cmd As New OleDbCommand(sql, conn)
Dim dob = DateTime.Parse(txtAddDOB.Text)
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddEmployeeID", .OleDbType = OleDbType.VarChar, .Size = 20, .Value = txtAddEmployeeID.Text})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddForename", .OleDbType = OleDbType.VarWChar, .Size = 255, .Value = txtAddForename.Text})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddSurname", .OleDbType = OleDbType.VarWChar, .Size = 255, .Value = txtAddSurname.Text})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddDOB", .OleDbType = OleDbType.Date, .Value = dob})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddUserTier", .OleDbType = OleDbType.VarChar, .Size = 20, .Value = txtAddUserTier.Text})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddContactID", .OleDbType = OleDbType.Integer, .Value = contactId})
conn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub
Sub AddContactToDatabase(contactId As Integer)
Dim sql = "INSERT INTO tblContacts (ContactID, Address, Postcode, Email, Mobile_Number) VALUES (#AddContactID, #AddAddress, #AddPostcode, #AddEmail, #AddMobileNo)"
Using conn As New OleDbConnection(connStr),
cmd As New OleDbCommand(sql, conn)
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddContactID", .OleDbType = OleDbType.Integer, .Value = contactId})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddAddress", .OleDbType = OleDbType.VarWChar, .Size = 255, .Value = txtAddAddress.Text})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#txtAddPostcode", .OleDbType = OleDbType.VarChar, .Size = 20, .Value = txtAddPostcode.Text})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddEmail", .OleDbType = OleDbType.VarWChar, .Size = 255, .Value = txtAddEmail.Text})
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#AddMobileNo", .OleDbType = OleDbType.VarChar, .Size = 20, .Value = txtAddMobileNumber.Text})
conn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub
Sub AddStaffMember()
Dim sql = "SELECT COUNT(*) FROM tblContacts"
Dim contactID As Integer
Using conn As New OleDbConnection(connStr),
cmd As New OleDbCommand(sql, conn)
conn.Open()
contactID = Convert.ToInt32(cmd.ExecuteScalar()) + 1
End Using
AddStaffMemberToDatabase(contactID)
AddContactToDatabase(contactID)
End Sub
Private Sub btnAddStaffMember_Click(sender As Object, e As EventArgs) Handles btnAddStaffMember.Click
AddStaffMember()
Me.Hide()
StaffDB_Add_Staff_Security_Question.Show() 'Open the Add Security Question Screen
End Sub
End Class
The Using statement makes sure that "unamanaged resources" are released when the code has finished with them.
Note that you will need to provide a more specific and robust way of parsing the DOB text (e.g. DateTime.TryParseExact). Also, the database types and sizes need to be edited to match the declarations in the database.
I inherited an old VB Website the uses ExecuteNonQuery to modify passwords. In our production environment, sql server 2008 R2, I've had recent reports of broken functionality. It turns out the ExecuteNonQuery is returning -1 when in fact the data is getting updated (a single row). When I copied the data to our dev environment, the rows affected is 1 as expected. We have a different service packs applied (4XXX vs 6XXX) and I wonder if this is the issue? I modified the code to use ExecuteScalar to inspect the RowCount, and this is working. But I shouldn't have to do so. Any insight? I have now idea how long this has been broken.
Here's the original code, that returns -1 erroneously. It is not calling a stored procedure and there are no triggers involved.
Dim cmd As SqlCommand = New SqlCommand("UPDATE UserMaster " & _
" SET Password = #Password, LastPasswordChangedDate = #LastPasswordChangedDate " & _
" WHERE Username = #UserName AND ApplicationName = #ApplicationName ", conn)
cmd.Parameters.Add("#Password", SqlDbType.VarChar, 255).Value = CreateHash(newPwd)
cmd.Parameters.Add("#LastPasswordChangedDate", SqlDbType.DateTime).Value = DateTime.Now
cmd.Parameters.Add("#Username", SqlDbType.VarChar, 255).Value = username.TrimEnd
cmd.Parameters.Add("#ApplicationName", SqlDbType.VarChar, 255).Value = Left(pApplicationName, 1)
Dim rowsAffected As Integer = 0
Try
conn.Open()
rowsAffected = cmd.ExecuteNonQuery()
This code returns a 1 as expected:
Dim cmd As SqlCommand = New SqlCommand("UPDATE UserMaster " & _
" SET Password = #Password, LastPasswordChangedDate = #LastPasswordChangedDate " & _
" WHERE Username = #UserName AND ApplicationName = #ApplicationName ; select ##rowcount", conn)
cmd.Parameters.Add("#Password", SqlDbType.VarChar, 255).Value = CreateHash(newPwd)
cmd.Parameters.Add("#LastPasswordChangedDate", SqlDbType.DateTime).Value = DateTime.Now
cmd.Parameters.Add("#Username", SqlDbType.VarChar, 255).Value = username.TrimEnd
cmd.Parameters.Add("#ApplicationName", SqlDbType.VarChar, 255).Value = Left(pApplicationName, 1)
Dim rowsAffected As Integer = 0
Try
conn.Open()
rowsAffected = CType(cmd.ExecuteScalar(), Integer)
ExceuteNonQuery returns -1 for all stored procedures as per the Msdn documentation.
It will return the updated records' number only in case of a statement.