Concurrency violation: the DeleteCommand affected 0 records

K

k

-----------------------------------------------------------------
The PK in the oledbdeletecommand.parameters collection *appears* to have the
appropriate Primary Key to look for to delete, so I'm not sure why it's not
able to find the record to delete... After reloading the master form, the
datarow deletes and the dataadapter.update(me.ds) goes just fine.
-----------------------------------------------------------------

I have two forms in a master/detail relationship, with the master form's
dataset shared with the detail form. I use the form's currencymanagers to
synch the detail record, add a new row, etc. The database is Access, using
the Jet driver.

After creating a new record with "cm.AddNew()" in the detail form, the
following gives me the "affected 0 records" error:
1. update the database with the dataadapter via
"masterForm.da.update(masterForm.ds)"

2. use "@@Identity" to get the database's primary key just generated on
this database connection for my new row, and alter our dataset row's PK
field to conform with database by using "drCm.Item("PK") = newPK"

3. call cm.EndCurrentEdit() & drCm.acceptChanges() to set the row's state
from "Modified" to "Unchanged".

4. back in the master form, delete the new record via "dr.Delete()"

////////////////// This throws the Exception //////////////////
5. attempt to synch the datarow delete w/ the database by using the
dataadapter via:
"me.da.update(me.ds)"



Here are some code snippets:

mngUsers.vb
-------------------------------------
Private cmEmployees As CurrencyManager

Private Sub mngUsers_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Me.cmEmployees = CType(Me.BindingContext(Me.DsUsers1.Employees),
CurrencyManager)
'// some code snipped from here
End Sub

Private Sub btnNew_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnNew.Click
Dim myUser As New mngUsersNewEdit(mngUsersNewEdit.formAction.newUser)
Me.AddOwnedForm(myUser)
myUser.Show()
End Sub

Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnDelete.Click
Dim drCm As DataRow
drCm = CType(Me.cmEmployees.Current, DataRowView).Row

Try
drCm.Delete()
Me.OleDbDataAdapter1_Users.Update(Me.DsUsers1.Employees)
Catch ex As Exception
MessageBox.Show(ex.Message + vbCrLf + vbCrLf + ex.StackTrace)
End Try
End Sub



mngUsersNewEdit.vb
-----------------------------------
Private m_actionToTake As formAction
Private m_parent As mngUsers
Private cmEmployees As CurrencyManager
Private cmOwner As CurrencyManager

Private Sub mngUsersNewEdit_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Me.m_parent = Me.Owner
Me.cmEmployees =
CType(Me.BindingContext(Me.m_parent.DsUsers1.Employees), CurrencyManager)

'// If appropriate, Synchronize our Form to the record currently
selected in parent form
If m_actionToTake = formAction.editUser Then
'// set a currency manager for the owner form to find Form1's
current record position
cmOwner = CType(CType(Me.Owner,
masterdetailDeleteTest.mngUsers).BindingContext(Me.m_parent.DsUsers1.Employe
es), CurrencyManager)
'// synchronize the table record positions between form1 and form2
Me.cmEmployees.Position = Me.cmOwner.Position
Else
'// create a new itemOption
cmEmployees.AddNew()
'// set up default data so avoid DBnull conflicts
'// casting the currency manager and accessing it's 'row' object
allows us to access an item by column name.
Dim drNew As DataRow = CType(cmEmployees.Current, DataRowView).Row
drNew.Item("IsActive") = True
drNew.Item("Birthdate") = "1/1/1970"
End If

'// Set our databindings
Me.tbEmployeeID.DataBindings.Add("text", Me.m_parent.DsUsers1.Employees,
"EmployeeID")
Me.tbFirstName.DataBindings.Add("text", Me.m_parent.DsUsers1.Employees,
"FirstName")
'// etc. w/ the databinding

End Sub

Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnOK.Click
Me.cmEmployees.EndCurrentEdit()
Try
Me.m_parent.OleDbDataAdapter1_Users.Update(Me.m_parent.DsUsers1)
If Me.m_actionToTake = formAction.newUser Then
'// To avoid having the autogenerated primary key in dataset out
of synch with database,
'// retrieve the newly created database PK and update our
dataset's PK with it.
'// Include a variable and a command to retrieve the
autogenerated primary key value
'// (identity value) from the Access database.
'// cf.
ms-help://MS.VSCC/MS.MSDNVS/cpguide/html/cpconretrievingidentityorautonumber
values.htm
Dim newID As Integer = 0
Dim idCMD As OleDbCommand = New OleDbCommand("SELECT
@@IDENTITY", Me.m_parent.OleDbConnection1)

'// Retrieve the identity value.
newID = CInt(idCMD.ExecuteScalar())

'// Assign retrieved autonumber to our new row's primary key.
Dim drCm As DataRow = CType(Me.cmEmployees.Current,
DataRowView).Row '// datarow to inspect our current row
drCm.Item("EmployeeID") = newID '// push DB's new PK to
row's "Current", "Original", and "Default" values

'// Roll our PK value change into the row's "original version."
'// The deleteCommand uses the original row PK values to do the
deletion,
'// which may be out of synch with the database. If so, the
dataset would throw an
'// exception when the database (looking for the wrong PK) could
still not find the row to delete.
cmEmployees.EndCurrentEdit() '// allow this row's changes
to remain
drCm.AcceptChanges() '// set row's state from "Modified" to
"Unchanged" to prevent unneccessary labor
End If
Catch ex As Exception
MessageBox.Show(ex.Message + vbcrlf + vbcrlf + ex.StackTrace)
End Try

Me.Owner.Focus()
Me.Close()
End Sub
 
M

Miha Markic

Hi k,

Check out the command parameters. If there is any of OleDbType.DBDate,
change it to OleDbType.Date.
 
K

k

Miha,

I tried changing the date field to OleDbType.Date, but that didn't resolve
the issue. I also tried removing the date field altogether. Again, it
didn't
resolve the issue. I continue to recieve the same error...

Have you seen this weirdness caused by anything else?

k
 
K

k

It's just the standard wizard generated deleteCommand. Here's the code
(watch for text wrapping):

I would love to see what SQL is actually sent to the database, but it's not
SQL server, so I dont' have the SQL profiler available. Is there perhaps a
way to do something similar with MS Acess?


'
'OleDbDeleteCommand1
'
Me.OleDbDeleteCommand1.CommandText = "DELETE FROM Employees WHERE
(EmployeeID = ?) AND (City = ? OR ? IS NULL AND City " & _
"IS NULL) AND (FirstName = ? OR ? IS NULL AND FirstName IS NULL) AND
(IsActive = " & _
"?) AND (IsLoggedIn = ?) AND (LastName = ? OR ? IS NULL AND LastName IS
NULL) AND" & _
" (Pswd = ? OR ? IS NULL AND Pswd IS NULL) AND (SSN = ? OR ? IS NULL AND SSN
IS N" & _
"ULL) AND (State = ? OR ? IS NULL AND State IS NULL) AND (StreetAddress = ?
OR ? " & _
"IS NULL AND StreetAddress IS NULL) AND (SwipeCardID = ? OR ? IS NULL AND
SwipeCa" & _
"rdID IS NULL) AND (Usrname = ? OR ? IS NULL AND Usrname IS NULL) AND
(ZipCode = " & _
"? OR ? IS NULL AND ZipCode IS NULL)"
Me.OleDbDeleteCommand1.Connection = Me.OleDbConnection1
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_EmployeeID",
System.Data.OleDb.OleDbType.Integer, 0,
System.Data.ParameterDirection.Input, False, CType(10, Byte), CType(0,
Byte), "EmployeeID", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_City",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"City", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_City1",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"City", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_FirstName",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"FirstName", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_FirstName1",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"FirstName", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_IsActive",
System.Data.OleDb.OleDbType.Boolean, 2,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"IsActive", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_IsLoggedIn",
System.Data.OleDb.OleDbType.Boolean, 2,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"IsLoggedIn", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_LastName",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"LastName", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_LastName1",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"LastName", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_Pswd",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"Pswd", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_Pswd1",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"Pswd", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_SSN",
System.Data.OleDb.OleDbType.VarWChar, 11,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"SSN", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_SSN1",
System.Data.OleDb.OleDbType.VarWChar, 11,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"SSN", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_State",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"State", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_State1",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"State", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_StreetAddress",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"StreetAddress", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_StreetAddress1",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"StreetAddress", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_SwipeCardID",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"SwipeCardID", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_SwipeCardID1",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"SwipeCardID", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_Usrname",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"Usrname", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_Usrname1",
System.Data.OleDb.OleDbType.VarWChar, 50,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"Usrname", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_ZipCode",
System.Data.OleDb.OleDbType.VarWChar, 10,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"ZipCode", System.Data.DataRowVersion.Original, Nothing))
Me.OleDbDeleteCommand1.Parameters.Add(New
System.Data.OleDb.OleDbParameter("Original_ZipCode1",
System.Data.OleDb.OleDbType.VarWChar, 10,
System.Data.ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte),
"ZipCode", System.Data.DataRowVersion.Original, Nothing))
 
M

Miha Markic

Hi k,

It is a bit hard to see where the trouble lies.
You might try removing "AND" parts form DELETE statament one by one and see
which one is causing problems.
 
K

k

Ok, problem resolved. Thank you Miha, for your support.


I figured it out by hooking up the datatable to a datagrid and carefully
looking at the boolean fields checkboxes, and then manually altering the
deleteCommand to verify. Here's what was going on:

When the new record was created in the dataset, there was a field which was
*not getting initialized* (big rule to never forget) by the detail form,
because it was not attatched to a GUI control, and was overlooked. You
wouldn't think this would be a big deal, BUT... This field was a boolean.

Boolean fields can either be True, False, Null or Indeterminate.

The deleteCommand generated by the wizard was looking for a record in the
database table whose field value was either True, False, or NULL. However,
the wizard created dataset did not have a default value for this field, so
it set it to "Indeterminate." Therefore, when the deleteCommand could not
find a matching record the dataAdapter threw the error "Concurrency
violation: the DeleteCommand affected 0 records"


////////////////////////////////////////////////////////////////////////
// Two ways to address the problem //
////////////////////////////////////////////////////////////////////////

Either open the "xsd" file and give the appropriate "xs: element" with a
default value of 0 or 1,
like this:
<xs:element name="IsLoggedIn" type="xs:boolean" minOccurs="0"
default="0" />

OR

Grab a reference to the newly added row, and use it's "item" property to
force the datarow's field value to "True" or "False"
like this:
cm.AddNew()
Dim drNew as DataRow = CType(cm.current, DataRowView).Row
drNew.Item("IsLoggedIn")=True


k
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top