index > .NET Framework Data Access and Storage > TableAdapter insert/update/delete order

TableAdapter insert/update/delete order

Ok, I finally was able to get it to work after some more research. I will summarize my solution here in case someone needs it. And I still would like some help on making this solution cleaner.

a- add a partial class of the table adapter to help expose the data adapter (code generator makes it private)

namespace InspectionTableAdapters { // name space comes as is from the generated file

public partial class InspectionTableAdapter : Component { // same class header as from the generated file.

public OleDbDataAdapter Adapter2 {

get { return Adapter; } // not _adapter since Adapter has some logic

} } }

b- in the code where you update the DB

public class DataAccess
{

private static OleDbConnection connection = null; // some sort of global variable

public static void updateInspectionAndChildren(Inspection inspectionDS){
InspectionTableAdapter inspectionTableAdapter = new InspectionTableAdapter();
inspectionTableAdapter.Adapter2.RowUpdated += new System.Data.OleDb.OleDbRowUpdatedEventHandler(Adapter2_RowUpdated); ;

DataRow[] inspection_newRecords = inspectionDS._Inspection.Select("", "", DataViewRowState.Added);

connection = inspectionTableAdapter.Connection; // so that the handler can use the same connection!!
inspectionTableAdapter.Update(inspection_newRecords);
inspectionDS._Inspection.AcceptChanges();
}

static void Adapter2_RowUpdated(object sender, System.Data.OleDb.OleDbRowUpdatedEventArgs e){

if (e.StatementType == StatementType.Insert){
OleDbCommand cmdNewID = new OleDbCommand("SELECT @@IDENTITY", connection);
// Retrieve the Autonumber and store it in the ID column.
e.Row["Id"] = (int)cmdNewID.ExecuteScalar();
e.Status = UpdateStatus.SkipCurrentRow;
}

}

Where I need help cleaning is how can i get rid of the connection variable that i used as a global variable between where I call the update method and the handler??

AhmedHassan

I was able to expose the data adapter hidden by the table adapter, then reference the RowUpdated adapter event in the code that handles the loading of data that's built in a disconnected state (batch loaded). Here's a translation to VB.NET with some additional notes:

Let's say your dataset is named "MyDataset.xsd" and the table within the dataset you are loading is "MyTable". The data adapter for the table is wrapped and hidden by a table adapter called "MyTableTableAdapter" in the "MyDataSetTableAdapters" namespace in the "MyDataset.Designer.vb" (this file is auto-generated...changes will be wiped out so don't change it).

Add the partial public class to file "MyDataset.vb" and expose the data adapter as "MyAdapter":

Namespace MyDataSetTableAdapters
Partial Public Class MyTableTableAdapter
Public ReadOnly Property MyAdapter() As System.Data.SqlClient.SqlDataAdapter
Get
If (Me._adapter Is Nothing) Then
Me.InitAdapter()
End If
Return Me._adapter
End Get
End Property
End Class
End Namespace

In the code that calls the table adapter update function (the code that manages the batch load), add the RowUpdated event. This assumes you've added a reference to the table adapter as "MyTableTableAdapter1":

AddHandler Me.MyTableTableAdapter1.MyAdapter.RowUpdated, AddressOf RowUpdated

In the same file, add the RowUpdated sub:

Private Shared Sub RowUpdated(ByVal sender As Object, ByVal e As SqlClient.SqlRowUpdatedEventArgs)
If e.StatementType = StatementType.Insert Then e.Status = UpdateStatus.SkipCurrentRow
End Sub

bholmes

I was having exactly the same problems as described in the first post. Thanks for the help. It's now sorted out.

As a matter of interest, the concurrency error (for me, at least) was as a result of having deletes cascaded in SQL Server as well as on the dataset i.e. the constraint is declared with 'ON DELETE CASCADE' in the table definition. The concurrency problem is eliminated when deletes are handled in the correct order (bottom-up).

Cheers!

chisanga

I have implemented what you suggest in your very useful post but I am experiencing a bug that I am having problems understanding and satisfactorily resolving.

It goes something like this:

I have a parent table and a child table with a foreign key relationship between them. They are in a SQL Server 2K database and are defined also in a strongly typed dataset. Cascading is set to happen in the dataset and the database.

I update the parent table and then I attempt to update the child table (in fact it is the added rows part that is attempted). On attempting this I get the following error: "INSERT statement conflicted with COLUMN FOREIGN KEY constraint 'FK_Child_Parent'. The conflict occurred in database 'Tests', table 'Parent', column 'ParentID'.\r\nThe statement has been terminated."

Now when investigating this in the Immediate Window I found that if I examined the contents of the row which the command was attempting to insert the new (positive) ID assigned by the database was in place correctly in both the Parent table and the Child table. This confused me greatly as I could see no reason given this why their might be a conflict. I ran a Profiler trace using SQL Profiler and saw that the Update command was passing the original (negative) ID for the Parent row when trying to insert the row for the child.

I am having real problems trying to reconcile why the dataset should show that the fkID is the new fkID whilst the TableAdapter.Update command should be using the old fkID.

I didn't leave my investigating there however but looked at the row which the ChildTable.Select("","", DataViewRowState.Added)) was referencing (obviously I thought it should be the same row, but just out of interest. What I found when I tried "((DataRow)(ChildTable.Select("","",DataViewRowState.Added))[0])" in the Immediate Window was that the row contained the error I was experiencing. I used the DataRow.ClearErrors() method to clear the error and the tried the DataRow.EndEdit() method. When I then retried the line of code (pressed F5) was that it inserted fine.

I don't want to have to iterate through each row in the child to call the EndEdit() method and I'm sure I'm missing what is probably a simple trick. I hope that you (or someone) can help me.

Many Thanks,

Neil.




Developer
NeilR

I too am in this "hell" and would appreciate assistance.

tblInvTrans (child)

tblPurchaseOrders(parent)

FK Insert & Delete set to cascade.

I current throw a foreign key constraint error as follows:

_________________________________________

System.Data.SqlClient.SqlException was caught
Class=16
ErrorCode=-2146232060
LineNumber=1
Message="The INSERT statement conflicted with the FOREIGN KEY constraint "FK_tblInvTrans_tblPurchaseOrders". The conflict occurred in database "RegalInventory", table "dbo.tblPurchaseOrders", column 'PurchaseOrderID'.
The statement has been terminated."
Number=547
Procedure=""
Server="regdc1"
Source=".Net SqlClient Data Provider"
State=0
StackTrace:
at System.Data.Common.DbDataAdapter.UpdatedRowStatusErrors(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, Int32 commandCount)
at System.Data.Common.DbDataAdapter.UpdatedRowStatus(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, Int32 commandCount)
at System.Data.Common.DbDataAdapter.Update(DataRow[] dataRows, DataTableMapping tableMapping)
at System.Data.Common.DbDataAdapter.Update(DataRow[] dataRows)
at Regal_Raw_Inventory.PODataSetTableAdapters.tblInvTransTableAdapter.Update(DataRow[] dataRows) in C:\Documents and Settings\mtompkins.PURCHASE\Desktop\Regal Visual Basic\Regal Raw Inventory\Regal Raw Inventory\PODataSet.Designer.vb:line 3171
at Regal_Raw_Inventory.Form1.PoTabSave() in C:\Documents and Settings\mtompkins.PURCHASE\Desktop\Regal Visual Basic\Regal Raw Inventory\Regal Raw Inventory\Form1.vb:line 155
______________________________________________

The code for the update looks as follows -

If tried many iterations to work through this and have left them commented in the code - all to no avail.

[code]

Private Sub PoTabSave()

Me.Validate()

'Not calling EndEdit will not capture changes that have been made

Me.TblInvTransBindingSource.EndEdit()

Me.TblPurchaseOrdersBindingSource.EndEdit()

'Dim deletedInvTrans As PODataSet.tblInvTransDataTable = _ 'CType( _

'PODataSet.tblInvTrans.GetChanges(Data.DataRowState.Deleted) ', _

''PODataSet.tblInvTransDataTable)

Dim deletedInvTrans As PODataSet.tblInvTransDataTable = _

PODataSet.tblInvTrans.GetChanges(Data.DataRowState.Deleted)

Dim delPO As PODataSet.tblPurchaseOrdersDataTable = _

PODataSet.tblPurchaseOrders.GetChanges(Data.DataRowState.Deleted)

Dim newInvTrans As PODataSet.tblInvTransDataTable = _

PODataSet.tblInvTrans.GetChanges(Data.DataRowState.Added)

Dim newPO As PODataSet.tblPurchaseOrdersDataTable = _

PODataSet.tblPurchaseOrders.GetChanges(Data.DataRowState.Added)

Dim modifiedInvTrans As PODataSet.tblInvTransDataTable = _

PODataSet.tblInvTrans.GetChanges(Data.DataRowState.Modified)

Dim modPO As PODataSet.tblPurchaseOrdersDataTable = _

PODataSet.tblPurchaseOrders.GetChanges(Data.DataRowState.Modified)

' Using scope As Transactions.TransactionScope = _

' New Transactions.TransactionScope()

Try

' Remove all deleted orders from the tblInvTrans table

If deletedInvTrans IsNot Nothing Then

'Me.TblInvTransTableAdapter.Update(deletedInvTrans)

Me.TblInvTransTableAdapter.Update(deletedInvTrans.Select("", "", DataViewRowState.Deleted))

End If

'Update the PO table

'Me.TblPurchaseOrdersTableAdapter.Update(PODataSet.tblPurchaseOrders)

'Should be able to do this by updating tblPO but will break it down

If delPO IsNot Nothing Then

Me.TblPurchaseOrdersTableAdapter.Update(delPO.Select("", "", DataViewRowState.Deleted))

End If

If newPO IsNot Nothing Then

Me.TblPurchaseOrdersTableAdapter.Update(newPO.Select("", "", DataViewRowState.Added))

End If

If modPO IsNot Nothing Then

Me.TblPurchaseOrdersTableAdapter.Update(modPO.Select("", "", DataViewRowState.ModifiedCurrent))

End If

'Add new orders to the InvTrans table

If newInvTrans IsNot Nothing Then

' Me.TblInvTransTableAdapter.Update(newInvTrans)

Me.TblInvTransTableAdapter.Update(newInvTrans.Select("", "", DataViewRowState.Added))

End If

'Update all modified InvTrans

If modifiedInvTrans IsNot Nothing Then

'Me.TblInvTransTableAdapter.Update(modifiedInvTrans)

Me.TblInvTransTableAdapter.Update(modifiedInvTrans.Select("", "", DataViewRowState.ModifiedCurrent))

End If

Me.PODataSet.AcceptChanges()

Catch ex As Exception

MsgBox("Update To Remote Server Failed" & vbCrLf & ex.ToString())

Finally

If deletedInvTrans IsNot Nothing Then

deletedInvTrans.Dispose()

End If

If delPO IsNot Nothing Then

delPO.Dispose()

End If

If newInvTrans IsNot Nothing Then

newInvTrans.Dispose()

End If

If newPO IsNot Nothing Then

newPO.Dispose()

End If

If modifiedInvTrans IsNot Nothing Then

modifiedInvTrans.Dispose()

End If

If modPO IsNot Nothing Then

modPO.Dispose()

End If

End Try

'scope.Complete()

'End Using

End Sub

[/code]




Mark Tompkins
Mark Tompkins
reply 25
first  previous  [1]  2  

You can use google to search for other answers

 

More Articles

• Odbc and OleDb to VFP with tables of 64 or more fields and record...
• DataTable Stripping time from DateTime
• Test if a MDB is Corrupted
• GridView in Web Application Not Deleting Rows
• Bulk copy data between ODBC sources
• Simple Update from a VS 2005 vb project to an mdb?
• ODbc Connection String to Excel
• Relationships in Typed Datasets
• DESCRIBE STATEMENT
• How can i change ConnectionString at runtime in Data Access Appli...
Bookmark and Share
Welcome to Bokebb   New Update  
 

New Articles

• after publish the program, if i wanna ch
• Sql server 2005 ==> 1000 times slowe
• Do DataTables need locks?
• getting info from database
• Obtain dimension in byte of a record
• Getting deleted child rows for a "S
• Visual Studio 2003 with SQL Server 2005
• how to use where clause in data adapter
• DataSet or DataReader
• Error opening a sample .mdf database
• Pragmatics of using IDbComand for direct
• insert, delete, update in a datagrid and
• How to create a script for creation of u
• Adding column to a dbf file
• table adapters - update

Hot Articles

• Imports cell from DataTable
• Program hangs on remote connection when
• Using A Variable In An Excel Query For V
• Sql server 2005 ==> 1000 times slowe
• Problem in element order - while writtin
• Ado.Net 2.0 Provider compliance?
• default value 0
• System.NullReferenceException: Using Dat
• Searching Database for results
• Enterprise Library problem with oracle 1
• Retrieving CLOB data from Informix
• Fulfill inner joins and queries in a 3-t
• Number of Query values and destination f
• Inserting a row duplicates this row
• Add new Record in VB 2005

Recommend Articles

• DataSet Vs DataReader????
• Help with queries
• interacting applications
• Com Exception is unhandeled while execut
• I had the same problem
• Problem with Transactions C# and Sql Exp
• Trying to insert non-latin characters in
• data objects and their limitations
• Asp / Ado databinding to Sql database
• - Is there a difference between Dataread
• got a form, got a database, the two don'
• Framework Versions
• return output Inserted.ColName value int
• OCI-22053: overflow error caused when re
• Save DataTable to new Databasefile