Oracle transaction Rollback doesn't work - vb.net

I created an Oracle transaction trying to save some data in two tables and I caused an error at the second procedure to call the rollback and check if it works.
The first procedure creates a job in USER_SCHEDULER_JOBS using the sys.dbms_scheduler.create_job.
Private Function CreateJobDef() As Integer
Try
Cursor.Current = Cursors.WaitCursor
conn = New OracleConnection
conn.ConnectionString = gApp.ConnectString
conn.Open()
Dim cmd As OracleCommand = conn.CreateCommand()
Dim oraclTrans As OracleTransaction
oraclTrans = conn.BeginTransaction()
cmd.Transaction = oraclTrans
Try
cmd.CommandText = "TEST.CREATE_JOB_SCHEDULE"
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Clear()
OracleCommandBuilder.DeriveParameters(cmd)
cmd.Parameters("in_job_name").Value = txtName.Text
cmd.Parameters("in_schedule_name").Value = cboSchedule.SelectedValue
cmd.Parameters("in_enabled").Value = If(chkEnabled.Checked, 1, 0)
cmd.Parameters("in_comments").Value = txtComments.Text
cmd.ExecuteNonQuery()
'Everything is OK
'-----------------------------------------------
cmd.CommandText = "TEST.Update_Job_Def"
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Clear()
OracleCommandBuilder.DeriveParameters(cmd)
cmd.Parameters("in_job_id").Value = "WQwqwq" 'I set this to a string to cause an error in the second procedure to check the rollback
cmd.Parameters("in_job_name").Value = txtName.Text
cmd.Parameters("in_job_type").Value = cboType.SelectedItem
cmd.Parameters("in_report_nav_id").Value = cboReport.SelectedValue
cmd.Parameters("in_mail_address_to").Value = txtMailTo.Text
cmd.ExecuteNonQuery()
oraclTrans.Commit()
Catch ex As OracleException
Msgbox(ex.ToString)
oraclTrans.Rollback()
Catch ex As Exception
Msgbox(ex.ToString)
oraclTrans.Rollback()
Finally
conn.Close()
If conn IsNot Nothing Then conn.Dispose()
If cmd IsNot Nothing Then cmd.Dispose()
End Try
Catch ex As OracleException
Msgbox(ex.ToString)
Catch ex As Exception
Msgbox(ex.ToString)
Finally
Cursor.Current = Cursors.Default
End Try
End Function
The problem is that the first procedure is create a new Job, although I have caused an error at the second procedure and the rollback is called.
Any ideas?
Thanks

There is an implicit commit in a DDL statement and in many Oracle procedure calls that create or modify objects such as a scheduled job. Therefore you cannot rollback a job creation procedure.

Related

Insert records into a table from more than pc at same time

I want to insert from more one pc at the same time into the same table in sql server and vb.net.
Error:
Conflicts when inserting data at same time
Try
Dim com As New SqlCommand()
com.CommandType = CommandType.StoredProcedure
com.CommandText = "insertooks"
com.Parameters.AddWithValue("#MULTIINSERT_CODE", SqlDbType.NVarChar).Value = TextBox1.Text
com.Parameters.AddWithValue("#MULTIINSERT_NAME", SqlDbType.NVarChar).Value = TextBox2.Text
com.Parameters.AddWithValue("#MULTIINSERT_DATE ", SqlDbType.Date).Value = DateTimePicker1.Value
com.Connection = con
con.Open()
com.ExecuteNonQuery()
con.Close()
MsgBox("Record inserted successfully")
Catch ex As Exception
'Throw ex
MsgBox(ex.Message)
Finally
con.Close()
con.Dispose()
End Try
Stored Procedure:
ALTER PROCEDURE [dbo].[insertooks]
#MULTIINSERT_CODE NVARCHAR(50) = NULL ,
#MULTIINSERT_NAME NVARCHAR(50) = NULL ,
#MULTIINSERT_DATE DATETIME = NULL
AS
BEGIN
SET NOCOUNT ON
INSERT INTO MULTIINSERT_TB
(
MULTIINSERT_CODE,
MULTIINSERT_NAME,
MULTIINSERT_DATE
)
VALUES
(
#MULTIINSERT_CODE ,
#MULTIINSERT_NAME ,
#MULTIINSERT_DATE
)
END
Your connection object needs to be declared with a Using in the method where it is used so it can be closed and disposed.
Use Using...End Using blocks to ensure that your database objects are closed and disposed. Note the comma at the end of the Using; this includes the command in the the Using.
Pass the connection string directly to the constructor of the connection. Likewise, pass the CommandText and the connection directly to the constructor of the command.
This should be .Add method which takes the SqlDbType as the second parameter. The .AddWithValue method (which shouldn't be used with Sql Server) takes the value as the second parameter.
Never show a message box while a connection is open. The user could have gone to lunch and there sits your open connection. Actually, it will eventually time out but you get the point.
I hope the primary key of MULTIINSERT_TB is an identity field (auto-number) and you are not passing a value for it.
Private ConStr As String = "Your connection string"
Private Sub OpCode()
Try
Using con As New SqlConnection(ConStr),
com As New SqlCommand("insertooks", con)
com.CommandType = CommandType.StoredProcedure
com.Parameters.Add("#MULTIINSERT_CODE", SqlDbType.NVarChar).Value = TextBox1.Text
com.Parameters.Add("#MULTIINSERT_NAME", SqlDbType.NVarChar).Value = TextBox2.Text
com.Parameters.Add("#MULTIINSERT_DATE ", SqlDbType.Date).Value = DateTimePicker1.Value
con.Open()
com.ExecuteNonQuery()
End Using 'closes and disposes con and com
MsgBox("Record inserted successfully")
Catch ex As Exception
'Throw ex
MsgBox(ex.Message)
End Try
End Sub

How to show error message on forms project when its already catched in library

Have some windows form with nice circural progress bar which i show user during long database function process. There is also task which calls function which inside i got query with transaction and there is catch implemented to rollback if it fails and return either true/false about state of process after finished. I didn't place there memssage box to show error as it's not adviced to store message boxes along in library projects so i would like to show this error on my task level function (in catch). However since i am catching error inside my function i am not able to show it (catch it) on the task's catch. How to accomplish that?
The only idea in my head is to instead of returning only result also return catched error message with use of Tuple like this: Tuple(Of Boolean, String). So i would be able to return two things: result and error message text. I am not so sure if this is right way to do such things. Looking for your advice.
This comes from windows forms project:
Dim pic As New CircuralWindowsForms(eCircularProgressType.Donut)
Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
Dim resu = False
Try
resu = createArticle.ProcessArticle(data)
Catch sqlex As Exception
pic.Invoke(Sub() MessageBox.Show(pic, sqlex.Message))
Finally
'--Close form once done (on GUI thread)
pic.Invoke(New Action(Sub() pic.Close()))
End Try
Return resu
End Function)
'Show circural form
pic.ShowDialog()
Task.WaitAll(tsk)
if tsk.Result = true Then
...
This comes from library project:
Public Function ProcessArticle(data as Data) As Boolean
Dim result = false
Using connection As New SqlConnection(strcon)
Try
connection.Open()
Dim transaction As SqlTransaction
transaction = connection.BeginTransaction()
.....
transaction.Commit()
result=true
Catch ex As Exception
result = False
transaction.Rollback()
End Try
End Using
return result
End Function
Extended question a bit (discussion with sstan):
Public Sub DeleteAllRelated(varId As Integer)
Using con As New SqlConnection(strcon)
Dim commit As Boolean = True
con.Open()
Dim tran As SqlTransaction = con.BeginTransaction
Dim dt As New DataTable
dt = CType(New Variation_VariationAttributeDAL().GetAllByVariationId(varId), DataTable)
If dt IsNot Nothing Then
For Each row As DataRow In dt.Rows
If commit Then commit = commit And New Artikel_VariationDAL().DeleteByVariation_VariationAttribute(CInt(row(0)), tran)
Next
End If
If commit Then commit = commit And New Variation_VariationAttributeDAL().DeleteAllWhereVarId(varId, tran)
If commit Then commit = commit And Delete(varId, tran)
If commit Then commit = commit And New DALSubKategorie_Variation().Delete(varId, tran)
If commit Then
tran.Commit()
Else
tran.Rollback()
End If
End Using
End Sub
this is e.g for: If commit Then commit = commit And New DALSubKategorie_Variation().Delete(varId, tran)
Public Function Delete(varId As Integer, Optional transaction As SqlTransaction = Nothing) As Boolean
Dim result As Boolean = False
If transaction Is Nothing Then
Try
Using con As New SqlConnection(strcon)
Using cmd As New SqlCommand("DELETE FROM " & SharedData.Write.T(SharedData.Tables.SubKategorie_Variation) & " WHERE FK_Variation_ID=#FK_Variation_ID", con)
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("#FK_Variation_ID", varId)
con.Open()
Dim rowsAffected As Integer = cmd.ExecuteNonQuery()
con.Close()
result = True
End Using
End Using
Catch ex as Exception
Throw
End Try
Else
Using cmd As New SqlCommand("DELETE FROM " & SharedData.Write.T(SharedData.Tables.SubKategorie_Variation) & " WHERE FK_Variation_ID=#FK_Variation_ID", transaction.Connection)
cmd.Transaction = transaction
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("#FK_Variation_ID", varId)
Dim rowsAffected As Integer = cmd.ExecuteNonQuery()
result = True
End Using
End If
Return result
End Function
You're right that it would be wrong for your library to display message boxes directly. But that doesn't mean it should swallow exceptions either. In, fact, quite the opposite: you really should let the exception bubble up to the caller, and let the caller decide what to do with it.
With that in mind, I would change the ProcessArticle function to the following:
Public Sub ProcessArticle(data as Data)
Using connection As New SqlConnection(strcon)
Try
connection.Open()
Dim transaction As SqlTransaction
transaction = connection.BeginTransaction()
' .....
transaction.Commit()
Catch ex As Exception
transaction.Rollback()
Throw 'Rethrow exception. The caller can decide what to do with it.
End Try
End Using
End Sub
Notice how the exception is still caught to enable the transaction rollback, but the exception is rethrown so that the caller can catch it. This in turn means that you no longer need to return a boolean to indicate success or failure.
EDIT
Not directly related to your question, but I would further move the code around a little bit so that I don't accidentally try to rollback a transaction before it has even begun (With you current code, ask yourself what would happen if an error occurred while trying to open the connection?):
Public Sub ProcessArticle(data as Data)
Using connection As New SqlConnection(strcon)
connection.Open()
Using transaction = connection.BeginTransaction()
Try
' do work here
transaction.Commit()
Catch ex As Exception
transaction.Rollback()
Throw 'Rethrow exception. The caller can decide what to do with it.
End Try
End Using
End Using
End Sub
EDIT 2
More on the Throw Statement:
A Throw statement with no expression can only be used in a Catch statement, in which case the statement rethrows the exception currently being handled by the Catch statement.
EDIT 3: Simplified version of your last edit
Public Sub DeleteAllRelated(varId As Integer)
Using con As New SqlConnection(strcon)
con.Open()
Using transaction = connection.BeginTransaction()
Try
Dim dt As New DataTable
dt = CType(New Variation_VariationAttributeDAL().GetAllByVariationId(varId), DataTable)
If dt IsNot Nothing Then
For Each row As DataRow In dt.Rows
New Artikel_VariationDAL().DeleteByVariation_VariationAttribute(CInt(row(0)), tran)
Next
End If
New Variation_VariationAttributeDAL().DeleteAllWhereVarId(varId, tran)
Delete(varId, tran)
New DALSubKategorie_Variation().Delete(varId, tran)
'If we made it this far without an exception, then commit.
tran.Commit()
Catch ex As Exception
tran.Rollback()
Throw 'Rethrow exception.
End Try
End Using
End Using
End Sub
Public Sub Delete(varId As Integer, Optional transaction As SqlTransaction = Nothing)
If transaction Is Nothing Then
Using con As New SqlConnection(strcon)
Using cmd As New SqlCommand("DELETE FROM " & SharedData.Write.T(SharedData.Tables.SubKategorie_Variation) & " WHERE FK_Variation_ID=#FK_Variation_ID", con)
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("#FK_Variation_ID", varId)
con.Open()
Dim rowsAffected As Integer = cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
Else
Using cmd As New SqlCommand("DELETE FROM " & SharedData.Write.T(SharedData.Tables.SubKategorie_Variation) & " WHERE FK_Variation_ID=#FK_Variation_ID", transaction.Connection)
cmd.Transaction = transaction
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("#FK_Variation_ID", varId)
Dim rowsAffected As Integer = cmd.ExecuteNonQuery()
End Using
End If
End Sub
EDIT 4: Example of exception chaining
Public Sub ProcessArticle(data as Data)
Try
' do work here
Catch ex As Exception
' If you want the original error to go up to the "upper levels"
' but with additional information, you need to throw a new
' instance of an exception with a new message that contains the additional information
' but you need to pass the original exception as a parameter to the constructor
' so that exceptions get chained together.
' If an "upper level" caller catches the chained exception,
' doing "ex.ToString" will provide all the information.
' Try it out, see how it works.
Throw New Exception("put your additional information here", ex)
End Try
End Sub

vb.net how to show data from sql in lable

i want show my select syntac into lable but my code no work this only show 1 actualy data is 11
Try
If IsNothing(ds.Tables("kkpsurabaya")) = False Then
ds.Tables("kkpsurabaya").Rows.Clear()
End If
query = "SELECT count(total_telat) FROM kkpsurabaya WHERE LATE <=30 And Late >=1"
da = New SqlDataAdapter(query, conn)
da.Fill(ds, "kkpsurabaya")
Label7.Text = da.Fill(ds, "kkpsurabaya")
da.Dispose()
conn.Close()
Catch ex As Exception
FatalErrorOccured(ex)
End Try
You should not be using a data adapter and DataTable for this. That's for getting a tabular result set. If you want a single value then use a command and call ExecuteScalar.
Dim command As New SqlCommand(query, conn)
Label7.Text = command.ExecuteScalar().ToString()
To learn what ADO.NET objects to use in what situations, check out my examples here.
solved now
conn.Open()
query = "SELECT count(total_telat) as total_telat FROM kkpsurabaya WHERE total_telat <=30 and total_telat >=1"
cmd = New SqlCommand(query, conn)
Try
RD = cmd.ExecuteReader()
If RD.Read() Then
Label7.Text = RD.GetValue(0)
End If
RD.Close()
Catch ex As System.Exception
MsgBox(ex.Message)
End Try
conn.Close()

Variable is used before it has been assigned Null Reference Exception

I am having trouble fixing this null reference exception
Dim Conn As New OleDb.OleDbConnection
Dim Trans As OleDb.OleDbTransaction
Try
' create the stream writer object
Dim FS As New System.IO.StreamReader(FileName)
' open DB connection and start a transaction
Dim Tmp As New POSDSTableAdapters.ItemsTableAdapter
Conn.ConnectionString = Tmp.Connection.ConnectionString
Conn.Open()
Trans = Conn.BeginTransaction
' clear all tables
Dim CMD As New OleDb.OleDbCommand
CMD.CommandText = " delete from ReciptDetails"
CMD.Connection = Conn
CMD.Transaction = Trans
CMD.ExecuteNonQuery()
CMD.Dispose()
CMD = New OleDb.OleDbCommand
CMD.CommandText = " delete from Recipts"
CMD.Connection = Conn
CMD.Transaction = Trans
CMD.ExecuteNonQuery()
CMD.Dispose()
CMD = New OleDb.OleDbCommand
CMD.CommandText = " delete from items"
CMD.Connection = Conn
CMD.Transaction = Trans
CMD.ExecuteNonQuery()
CMD.Dispose()
CMD = New OleDb.OleDbCommand
CMD.CommandText = " delete from RestorantTable"
CMD.Connection = Conn
CMD.Transaction = Trans
CMD.ExecuteNonQuery()
CMD.Dispose()
CMD = New OleDb.OleDbCommand
CMD.CommandText = " delete from [Values]"
CMD.Connection = Conn
CMD.Transaction = Trans
CMD.ExecuteNonQuery()
CMD.Dispose()
' load the tables
If Not LoadTableFromBackup(Conn, Trans, FS, "RestorantTable") Then
Trans.Rollback()
Conn.Close()
FS.Close()
Return False
End If
If Not LoadTableFromBackup(Conn, Trans, FS, "Values") Then
Trans.Rollback()
Conn.Close()
FS.Close()
Return False
End If
If Not LoadTableFromBackup(Conn, Trans, FS, "items") Then
Trans.Rollback()
Conn.Close()
FS.Close()
Return False
End If
If Not LoadTableFromBackup(Conn, Trans, FS, "Recipts") Then
Trans.Rollback()
Conn.Close()
FS.Close()
Return False
End If
If Not LoadTableFromBackup(Conn, Trans, FS, "ReciptDetails") Then
Trans.Rollback()
Conn.Close()
FS.Close()
Return False
End If
FS.Close()
Trans.Commit()
Conn.Close()
Return True
Catch ex As Exception
Trans.Rollback()
Conn.Close()
Return False
End Try
End Function
Based on your comment above, it would appear that Trans is never being assigned a value. Take a look at a smaller sample of your code:
Try
' create the stream writer object
Dim FS As New System.IO.StreamReader(FileName)
' open DB connection and start a transaction
Dim Tmp As New POSDSTableAdapters.ItemsTableAdapter
Conn.ConnectionString = Tmp.Connection.ConnectionString
Conn.Open()
Trans = Conn.BeginTransaction
' the rest of the code...
Catch ex As Exception
Trans.Rollback()
Conn.Close()
Return False
End Try
Your Catch block assumes that Trans and Conn will have values. However, if an exception is thrown before the line Trans = Conn.BeginTransaction then Trans will never have been assigned a value, so it will be null (Nothing in VB).
What's happening here is that something before that line is throwing an exception. But then your exception handler itself throws an entirely different exception. This is essentially obscuring the first exception, which is the actual error you're trying to find.
Using a debugger, put a break point on Trans.Rollback() and see what that original exception is, that's something you'll need to correct.
Aside from that, you can re-structure your Try/Catch blocks a bit to not assume that variables have values. Just to get you going as a beginner, at the very least you can do this in your Catch block:
Catch ex As Exception
If Trans Is Not Nothing Then
Trans.Rollback()
End If
If Conn Is Not Nothing Then
Conn.Close()
End If
Return False
End Try
It's not an error. It's a warning because you use trans before assigning it. Move Conn.Open()
and Trans = Conn.BeginTransaction before try and you will solve it.

No data available after an Insert operation VB.NET - Windows Forms and Web Service

VB.NET and ASMX Web Service. I am still having the same trouble of getting no data after an insert operation.
Here is my insert code:
Try
'create a MySqlCommand to represent the query
If sqlConn.State = ConnectionState.Closed Then
sqlConn = New MySqlConnection(conStr)
sqlConn.Open()
End If
Dim myCommand As MySqlCommand = New MySqlCommand(strQuery, sqlConn)
If myCommand.ExecuteNonQuery() <> 0 Then
Result = True
End If
Catch ex As Exception
Throw New ApplicationException("Error-luckie's server 2 " & ex.Message)
Finally
sqlConn.Close()
sqlConn.Dispose()
End Try
The strQuery will be a simple insert statement.
The code for retrieving data as a dataset is as follows
Public Function ExecuteQuery(ByVal strQuery As String) As DataSet
Dim ds As DataSet = New DataSet 'create a DataSet to hold the results
Try
'create a MySqlCommand to represent the query
If sqlConn.State = ConnectionState.Closed Then
sqlConn = New MySqlConnection(conStr)
sqlConn.Open()
End If
Dim sqlcmd As MySqlCommand = sqlConn.CreateCommand()
sqlcmd.CommandType = CommandType.Text
sqlcmd.CommandText = strQuery
'create a MySqlDataAdapter object
Dim sqlDa As MySqlDataAdapter = New MySqlDataAdapter
sqlDa.SelectCommand = sqlcmd
Try
'fill the DataSet using the DataAdapter
sqlDa.Fill(ds, "Results")
Catch ex As Exception
Throw New ApplicationException("Error-luckie's server 1 " & ex.Message)
End Try
Catch ex As Exception
Throw New ApplicationException("Error-luckie's server 2 " & ex.Message)
Finally
sqlConn.Close()
sqlConn.Dispose()
End Try
Return ds
End Function
I am Inserting data from one thread and retrieving data from another (not the same instance of connection is used).
This works perfect if I retrieve data after a 15 minutes gap.
But I want to get the result at once.
Please help.
I would change the method as below
Public Function ExecuteQuery(strQuery As String) As DataSet
Dim ds As New DataSet()
Try
Using con = New MySqlConnection(conStr) 'using statements...
Using cmd = New MySqlCommand(strQuery, con) 'using statements...
Using sqlDa = New MySqlDataAdapter(cmd) 'using statements...
sqlDa.Fill(ds, "Results")
End Using
End Using
End Using
Catch ex As Exception
Throw New ApplicationException("Error-luckie's server 1 " + ex.Message)
End Try
Return ds
End Function
Public Function ExecuteNonQuery(strQuery As String) As Boolean
Try
Using con = New MySqlConnection(conStr) 'using statements...
Using cmd = New MySqlCommand(strQuery, con) 'using statements...
con.Open()
If cmd.ExecuteNonQuery() > 0 Then ' I have change the condition
Return True
End If
End Using
End Using
Catch ex As Exception
Throw New ApplicationException("Error-luckie's server 2 " + ex.Message)
End Try
Return False
End Function