I've debugged my code that uses SqlCommandBuilder:
Dim daJoinTable As New SqlDataAdapter(sSQLSelect,connString)
Dim cbJoinTable As New SqlCommandBuilder(daJoinTable)
daJoinTable.Update(dsJoinTable.Tables(0))
and noticed that daJoinTable.UpdateCommand,InsertCommand and DeleteCommand are nulls, when I expected that they will be generated by SqlCommandBuilder.
Even if code works fine, I was curious, how dataadapter knows which update SQL command should be used. I found a good article about SqlCommandBuilder, but it doesn't go into this level of details.
With help of Reflector, I understood that SqlCommandBuilder constructor calls SetRowUpdatingHandler(DbDataAdapter adapter), to use protected DbCommandBuilder.RowUpdatingHandler when row is about to be updated.
The implementation of RowUpdatingHandler replaces null commands with commands generated by DbCommandBuilder for each updated row.