Dim cn As SqlConnection
Dim daParent, daChild As SqlDataAdapter
Dim ds As New DataSet()
Dim intPIDSelected As Integer = 0
Enum eTbl ' DataSet Tables enumeration
Parent
Child
End Enum
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Try ' Trap problems
' If you don't have the Biblio DB, change this to your own test DB (like Pubs)
' The application File menu has an entry that creates the test tables.
cn = New SqlConnection("server=demoserver;database=biblio;integrated security=sspi")
daParent = New SqlDataAdapter("SELECT PID, Name, State" _
& "FROM TestInsertParent", cn)
daChild = New SqlDataAdapter("SELECT CID, PID, ChildName, ChildAge" _
& " FROM TestInsertChild WHERE PID = @PIDWanted", cn)
daChild.SelectCommand.Parameters.Add("@PIDWanted", SqlDbType.Int)
' Set MissingSchemaAction to make sure multiple Fills don't add,
' but update data in DataTable
daChild.MissingSchemaAction = MissingSchemaAction.AddWithKey
GenerateCommands() ' Build the Action Commands
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub CreateRelations()
' Create inter-DataTable Relation objects between the Parent and Child tables
Dim colParent As DataColumn = _
ds.Tables(eTbl.Parent).Columns("PID")
Dim colChild As DataColumn = ds.Tables(eTbl.Child).Columns("PID")
' Create Relation along with Constraint
Dim daRel As New DataRelation("ParentToChildRelation", _
colParent, colChild, True)
ds.Relations.Add(daRel)
End Sub
Private Sub btnUpdate_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnUpdate.Click
Try
' Add parents first, then children
' Delete children first, then parents
' Use the Select method to return
' an array of rows to be updated or added
daParent.Update(ds.Tables(eTbl.Parent).Select("", "", _
DataViewRowState.Added Or DataViewRowState.ModifiedCurrent))
' Add, change or delete children
daChild.Update(ds.Tables(eTbl.Child))
' Delete any remaining parents
daParent.Update(ds.Tables(eTbl.Parent))
Catch exsql As SqlException
If exsql.Number = 547 Then
MsgBox("You must first delete child rows …. ")
Else
MsgBox(exsql.ToString)
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub btnSetAutoIncrement_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles btnSetAutoIncrement.Click
Try
' Set Autoincrement, seed, and step
With ds.Tables(eTbl.Parent).Columns("PID")
.AutoIncrement = True
.AutoIncrementSeed = CInt(txtAutoIncrementSeed.Text)
.AutoIncrementStep = CInt(txtAutoIncrementStep.Text)
End With
Catch ex As Exception
End Try
End Sub
Private Sub GenerateCommands()
' These commands were originally generated by the DACW and tuned
to remove
' some "imperfections" as discussed in the text of the article.
daParent.InsertCommand = New SqlCommand()
With daParent.InsertCommand
.CommandText = "INSERT INTO TestInsertParent(Name, State) " _
& " VALUES (@Name, @State); " _
& " SELECT PID, Name, State " _
& " FROM TestInsertParent WHERE (PID = SCOPE_IDENTITY())"
.Connection = cn
' Set Name, datatype, size and source column.
.Parameters.Add("@Name", System.Data.SqlDbType.VarChar, 50, "Name")
.Parameters.Add("@State", System.Data.SqlDbType.VarChar, 50, _ "State")
End With
daParent.UpdateCommand = New SqlCommand()
With daParent.UpdateCommand
.CommandText = "UPDATE TestInsert SET Name = @Name, " _
& " State = @State " _
& "WHERE (PID = @Original_PID) AND (Name = @Original_Name) " _
& " AND (State = @Original_State); " _
& "SELECT PID, Name, State FROM TestInsertParent WHERE (PID = @PID)"
.Connection = cn
.Parameters.Add("@Name", System.Data.SqlDbType.VarChar, " _
50, "Name")
.Parameters.Add("@State", System.Data.SqlDbType.VarChar, " _
50, "State")
.Parameters.Add(New System.Data.SqlClient.SqlParameter( _
"@Original_PID", System.Data.SqlDbType.Int, 4, System.Data.ParameterDirection.Input, False, _
CType(0, Byte), CType(0, Byte),"PID", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New System.Data.SqlClient.SqlParameter(_
"@Original_Name", System.Data.SqlDbType.VarChar, _
50, System.Data.ParameterDirection.Input, _
False, CType(0,Byte),CType(0,Byte),"Name", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_State", _
System.Data.SqlDbType.VarChar, 50, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "State", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add("@PID", System.Data.SqlDbType.Int, 4, "PID")
End With
daParent.DeleteCommand = New SqlCommand()
With daParent.DeleteCommand
.CommandText = "DELETE FROM TestInsertParent " _
& " WHERE (PID = @Original_PID) " _
& "AND (Name = @Original_Name) AND (State = @Original_State)"
.Connection = cn
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_PID", _
System.Data.SqlDbType.Int, 4, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "PID", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_Name", _
System.Data.SqlDbType.VarChar, 50, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "Name", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_State", _
System.Data.SqlDbType.VarChar, 50, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "State", _
System.Data.DataRowVersion.Original, Nothing))
End With
' Generate action Commands for the Child DataAdapter
daChild.InsertCommand = New SqlCommand()
With daChild.InsertCommand
.CommandText = "INSERT INTO TestInsertChild(PID, " _
& " ChildName, ChildAge) " _
& " VALUES (@PID, @ChildName, @ChildAge); " _
& " SELECT CID, PID, ChildName, ChildAge " _
& " FROM TestInsertChild WHERE (CID = SCOPE_IDENTITY())"
.Connection = cn
' Set Name, datatype, size and source column.
.Parameters.Add("@PID", System.Data.SqlDbType.Int, 2, "PID")
.Parameters.Add("@ChildName", System.Data.SqlDbType.VarChar, _
50, "ChildName")
.Parameters.Add("@ChildAge", System.Data.SqlDbType.TinyInt, _
1, "ChildAge")
End With
daChild.UpdateCommand = New SqlCommand()
With daChild.UpdateCommand
.CommandText = "UPDATE TestInsert SET PID = @PID, " _
& " Name = @ChildName, ChildAge = @ChildAge " _
& "WHERE (CID = @Original_CID) AND PID = @Original_PID) " _
& " AND (ChildName = @Original_Name) AND " _
& "(ChildAge = @ChildAge); " _
& "SELECT CID, PID, ChildName, ChildAge " _
& " FROM TestInsertChild WHERE (CID = @CID)"
.Connection = cn
.Parameters.Add("@PID", System.Data.SqlDbType.Int, 2, "PID")
.Parameters.Add("@ChildName", _
System.Data.SqlDbType.VarChar, 50, "ChildName")
.Parameters.Add("@ChildAge", _
System.Data.SqlDbType.TinyInt, 1, "ChildAge")
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_CID", _
System.Data.SqlDbType.Int, 4, _
System.Data.ParameterDirection.Input, False, _
CType(0, Byte), CType(0, Byte), "CID", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_PID", _
System.Data.SqlDbType.Int, 4, _
System.Data.ParameterDirection.Input, False, _
CType(0, Byte), CType(0, Byte), "PID", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_ChildName", _
System.Data.SqlDbType.VarChar, 50, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "ChildName", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New System.Data.SqlClient.SqlParameter("@Original_ChildAge", _
System.Data.SqlDbType.TinyInt, 1, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "ChildAge", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add("@CID", System.Data.SqlDbType.Int, 4, "CID")
End With
daChild.DeleteCommand = New SqlCommand()
With daChild.DeleteCommand
.CommandText = "DELETE FROM TestInsertChild " _
& " WHERE (CID = @Original_CID) " _
& " AND (PID = @Original_PID) " _
& " AND (ChildName = @Original_ChildName) " _
& " AND (ChildAge = @Original_ChildAge)"
.Connection = cn
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_CID", _
System.Data.SqlDbType.Int, 4, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "CID", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_PID", _
System.Data.SqlDbType.Int, 4, _
System.Data.ParameterDirection.Input, False, _
CType(0, Byte), CType(0, Byte), "PID", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_ChildName", _
System.Data.SqlDbType.VarChar, 50, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "ChildName", _
System.Data.DataRowVersion.Original, Nothing))
.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@Original_ChildAge", _
System.Data.SqlDbType.TinyInt, 1, _
System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "ChildAge", _
System.Data.DataRowVersion.Original, Nothing))
End With
End Sub
Private Sub mnuCreateTables_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles mnuCreateTables.Click
' This routine is used to create the test tables.
Dim strMakeTable As New StringBuilder()
Try
With strMakeTable
.Append("IF NOT EXISTS(SELECT * FROM Sysobjects " _
& " WHERE Name = 'TestInsertParent')")
.Append("BEGIN CREATE TABLE [TestInsertParent] (")
.Append(" [PID] [int] IDENTITY (1, 1) NOT NULL , ")
.Append(" [Name] [varchar] (50) NOT NULL , ")
.Append(" [State] [varchar] (50) NOT NULL , ")
.Append(" CONSTRAINT [PK_TestInsertParent] "_
& " PRIMARY KEY CLUSTERED ")
.Append(" ( [PID] ) ON [PRIMARY] ) ON [PRIMARY] END ")
' Create Child table with PK/FK relationship to Parent
.Append("IF NOT EXISTS(SELECT * FROM Sysobjects " _
& " WHERE Name = 'TestInsertChild')")
.Append("BEGIN CREATE TABLE [TestInsertChild] (")
.Append(" [CID] [int] IDENTITY (1, 1) NOT NULL , ")
.Append(" [PID] [int] NOT NULL , ")
.Append(" [ChildName] [varchar] (50) NOT NULL , ")
.Append(" [ChildAge] [tinyint] NOT NULL , ")
.Append(" CONSTRAINT [PK_TestInsertChild] "_
& " PRIMARY KEY CLUSTERED ")
.Append(" ( [CID] ) ON [PRIMARY], ")
.Append(" CONSTRAINT [FK_TestInsertChild_TestInsertParent] ")
.Append(" FOREIGN KEY([PID]) REFERENCES [TestInsertParent] "_
& " ([PID])) ")
.Append(" ON [PRIMARY] ")
.Append(" END ")
End With
cn.Open()
Dim cmdMakeTable As New SqlCommand(strMakeTable.ToString, cn)
cmdMakeTable.ExecuteNonQuery()
MsgBox("TestInsert Table created...")
Catch ex As Exception
MsgBox(ex.ToString)
Finally
cn.Close()
End Try
End Sub
Private Sub btnQuery_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnQuery.Click
Try
ds.Clear() ' Clear out any previous contents of the DataSet
' (Parent and Child tables cleared)
daParent.Fill(ds, "TestInsertParent") ' Fill the Parent DataSet
If daParent.TableMappings.Count = 0 Then
' Map logical to physical
daParent.TableMappings.Add("Table", "TestInsertParent")
End If
' Bind Parent Ds to the DataGrid
dgDisplay.DataSource = ds.Tables(eTbl.Parent)
' dgDisplay.DataMember = "TestInsertParent"
' Set the AutoIncrement values
btnSetAutoIncrement.PerformClick()
' Fetch the Child table data based on the selected Parent
If ds.Tables(eTbl.Parent).Rows.Count = 0 Then
MsgBox("Query did not return any rows. " _
& " You can add new rows to the Parent grid.")
End If
FetchChildRows()
If ds.Relations.Count = 0 Then
CreateRelations()
End If
Catch exSQL As SqlException
If exSQL.Number = 208 Then
MsgBox("Did you create the TestInsert table(s)? See the File menu.")
Else
MsgBox("Unexpected SqlExecption" & exSQL.ToString)
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub dgDisplay_Navigate(ByVal sender As Object, _
ByVal ne As System.Windows.Forms.NavigateEventArgs) _
Handles dgDisplay.Navigate
btnUpdate.Enabled = ds.HasChanges
If ne.Forward Then
FetchChildRows()
End If
End Sub
Private Sub FetchChildRows()
Try
' Extract PID from current row on DataGrid
intPIDSelected = CInt(ds.Tables(eTbl.Parent).Rows(dgDisplay.CurrentRowIndex)("PID"))
' Search for PID's children
daChild.SelectCommand.Parameters(0).Value = intPIDSelected
' Search for PID's children
' Fill the Child DataSet from the database
daChild.Fill(ds, "TestInsertChild")
' dgDisplay.DataSource = ds.Tables(eTbl.Parent)
' Rebind
dgDisplay.Update()
' Map logical Child table to physical table
If daChild.TableMappings.Count = 1 Then
daChild.TableMappings.Add("Table1", "TestInsertChild")
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub dgDisplay_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles dgDisplay.KeyDown
' If the user clicks Delete in the grid—
' be sure to fetch any child rows associated with this Parent
' to ensure that they get deleted before the parent.
If e.KeyValue = 46 Then ' Delete key
' Make sure that the child rows are included when Parent is deleted
FetchChildRows()
End If
End Sub
Private Sub mnyFileExit_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles mnuFileExit.Click
If ds.HasChanges Then
Dim resp As MsgBoxResult = MsgBox("Do you want to save " _
& "the changes made to your data?", MsgBoxStyle.YesNo _
Or MsgBoxStyle.Question, "Uncommited data")
If resp = MsgBoxResult.Yes Then
btnUpdate.PerformClick()
End If
End If
End
End Sub
End Class