En este ejemplo además utilizaré otros objetos, tales como BindingSource y BindingNavigator, asi que les dejo una explicación de cada uno con el código de ejemplo al final
CommandBuilder
Para utilizar un CommandBuilder deberan ejecutar la consulta de selección de registros con un DataAdapter ya que el comando SELECT es necesario para que el CommandBuilder sepa cómo debe crear los comandos tal como determina la ayuda de MSDN:
Para generar instrucciones SQL automáticamente para un DataAdapter, defina en primer lugar la propiedadSelectCommand del DataAdapter y, a
continuación, cree un objeto CommandBuilder y
especifique como argumento el DataAdapter para
el que CommandBuilder generará
automáticamente las instrucciones SQL.
Aquí dejo unos ejemplos de código de la misma página de MSDN
VB
' Assumes that connection is a valid
SqlConnection object
' inside of a Using block.
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
"SELECT * FROM dbo.Customers", connection)
Dim builder As SqlCommandBuilder = New
SqlCommandBuilder(adapter)
builder.QuotePrefix = "["
builder.QuoteSuffix = "]"
C#
// Assumes that connection is a valid SqlConnection object
// inside of a using block.
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT * FROM dbo.Customers", connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
builder.QuotePrefix = "[";
builder.QuoteSuffix = "]";
La consulta de selección se realiza porque el CommandBuilder funciona sobre un objeto
DataAdapter para crear los comandos de Transact SQL (TSQL)
que son necesarios para actualizar y para insertar registros en el origen de
datos, los cuales son cuatro objetos Command. Uno para selección de
registros, el SelectCommand(SC), uno para cuando se ingresó un registro en un
DataTable saber que hacer en la base de datos, el InsertCommand (IC), uno para
cuando se modificó un registro en el DataTable, el UpdateCommand (UC) y uno
para cuando el registro fue eliminado del DataTable, el DeleteCommand (DC).
Además, el DataAdapter tiene otros objetos llamados los TableMapping y ColumnMapping. Estos objetos te mapean los datos de los esquemas de las bases de datos a los datos de los esquemas de los DataSets.
Además, el DataAdapter tiene otros objetos llamados los TableMapping y ColumnMapping. Estos objetos te mapean los datos de los esquemas de las bases de datos a los datos de los esquemas de los DataSets.
El DataAdapter debe tener
para funcionar por lo menos el SC, este te genera los TableMappings y los
ColumnMappings y te permite relacionar la consulta del SC con los datos de los
DataTables. Pero cuando haces acciones sobre los DataTables y vas a actualizar
la base de datos debes tener los otros tres objetos Command establecidos. El
problema es que en este caso las sentencias se complican un poco por que debe
saber exáctamente como iba el registro originalmente y como está actualmente.
Es decir, debes por así decirlo, crear un mapeo hacia atrás con las sentencias
IC, UC y DC.
El CommandBuilder permite
que una vez tengas una sentencia SC, que se haga sobre una sola tabla y tenga
dentro de los campos selecionados los campos de llave primaria y los campos que
no tienen admiten null, puedas generar automáticamente las demás sentencias IC,
UC y DC.
El código es más o menos así:
[C#]
SqlConnection
cn = new SqlConnection("");
SqlDataAdapter
da = new SqlDataAdapter("SELECT * FROM Tabla", cn);
// Crear CommandBuilder. Al pasar como parámetro el
// DataAdapter toma el SC y genera los demás comandos
SqlCommandBuilder
cb = new SqlCommandBuilder(da);
da.InsertCommand
= cb.GetInsertCommand();
da.UpdateCommand
= cb.GetUpdateCommand();
da.DeleteCommand
= cb.GetDeleteCommand();
// Crear el
DataSet y llenarlo
DataSet ds
= new DataSet();
da.Fill(ds);
.
.
.
// Después de trabajar desconectado se actualizan los datos.
// El DataAdapter ya sabe como actualizarlos por que tiene
los comandos IC,
UC y DC
da.Update(ds);
[VB]
' Crear conexión y DataAdapter
Dim cn As
New SqlConnection("")
Dim da As
New SqlDataAdapter("SELECT * FROM Tabla", cn)
' Crear CommandBuilder. Al pasar como parámetro el
' DataAdapter toma el SC y genera los demás comandos
Dim cb As
New SqlCommandBuilder(da)
da.InsertCommand
= cb.GetInsertCommand()
da.UpdateCommand
= cb.GetUpdateCommand()
da.DeleteCommand = cb.GetDeleteCommand()
' Crear el DataSet y llenarlo
Dim ds As
New DataSet()
da.Fill(ds)
.
.
.
' Después de trabajar desconectado se actualizan los datos.
' El DataAdapter ya sabe como actualizarlos por que tiene
los comandos IC,
UC y DC
da.Update(ds)
Cosas sobre CommandBuilder:
- El CommandBuilder solo es útil cuando trabajas con una sola tabla y además la tabla debe tener definida una llave primaria.
- SelectCommand también debe devolver como mínimo una clave principal o una columna única. Si no hay ninguna, se genera una excepción InvalidOperation y no se genera ningún comando.
- Cuando se asocia con un objeto DataAdapter, el CommandBuilder genera automáticamente las propiedadesInsertCommand, UpdateCommand y DeleteCommand del objeto DataAdapter si son referencias nulas. Si ya existe algún objeto Command para una propiedad, se utilizará el objeto Command existente.
BindingSource
Es un objeto que hace de intermediario entre el control y el conjunto de
datos. Simplifica la conexión facilitando la actualización del contenido, la
notificación de cambios, etc. Se incluye la navegación, ordenación, filtrado y
actualización. El origen de datos subyacente se fija a través de uno de los
siguientes mecanismos:
- Usar
el método Add para añadir un elemento al componente BindingSource
- Asignar
a su propiedad DataSource una lista, objeto o un tipo.
Su funcionamiento permite enlazar universalmente todos los controles de
formularios Windows a orígenes de datos muy diversos.
Podemos imaginarnos al objeto BindingSource como el objeto que nos permite
movernos dentro de los registros existentes en el origen de datos al cual se
encuentra enlazado. Tal y como se indica en la ayuda de Visual Studio, el
objeto BindingSource está encapsulando el origen de datos que se ha
asignado a su propiedad DataSource, normalmente se tratará de un objeto DataTable,
que es el verdadero objeto que contiene los datos que han sido recuperados de
la base de datos fisica.
BindingNavigator
A partir de la versión 2005, Microsoft incorporó un nuevo objeto llamado
BindingNavigator el cual es un control basado en un objeto ToolStrip,
que permite realizar funciones de navegación por el conjunto de datos.
Estas funciones son: Primer registro,último, siguiente, anterior, número de
registros totales en el conjunto de datos y posición actual.
MissingSchemaAction.AddWithKey de DataAdapter
El objeto DataAdapter está optimizado para los escenarios de sólo lectura de forma predeterminada. El método Fill sólo recupera la parte del esquema necesaria para llenar un objeto DataSet. Para obtener el esquema adicional necesario para actualizar o validar los objetos DataSet se debe utilizar la enumeración AddWithKey de la propiedad MissingSchemaAction del DataAdapter.
Establecer la propiedad MissingSchemaAction del DataAdapter en AddWithKey es agregar información al esquema acerca de las claves principales, los campos AutoIncrement, los campos que aceptan valores NULL y los índices únicos.
El programa
Se presentarán los datos de la tabla img en la base de datos imagenes, para esto se creara un archivo app.config para guardar información de la conexión, los datos a presentar son tres: nombre, comentarios y ruta.
<connectionStrings>
<add name="conexion" connectionString="Data
Source=.\SQLEXPRESS;Initial Catalog=imagenes;Integrated Security=True"
providerName="System.Data.SqlClient" />
connectionStrings>
Esta será la aplicación, con su interfaz y el código, como ven se usa el Bindingnavigator para movilizarse entre los datos obtenidos por la consulta select, pero también se logra con los botones abajo de los TextBox, lo dejé así para que ustedes seleccionen el que prefieran porque obvio que es redundante utilizar los botones teniendo el Bindingnavigator, asi que fíjense en los comentarios del evento click de cada botón aparece la manera de moverse entre registros utilizando el BindingSource o el BindingContext (ambos necesitan el bs !!!)
Imports
System.Data
Imports
System.Data.SqlClient
Imports
System.Configuration
Public
Class Form1
Dim sql As SqlConnection
Dim da As SqlDataAdapter
Dim ds As New DataSet
Dim bs As New BindingSource
Dim dt As New DataTable
Private Sub Form1_Load(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
MyBase.Load
CargarDatos()
End Sub
Public Sub
Cargardatos()
sql
= New SqlConnection(s)
ConfigurarAdaptadorDatos()
da.Fill(dt)
bs.DataSource = dt
DataGridView1.DataSource = bs
BindingNavigator1.BindingSource = bs
TextBox1.DataBindings.Clear()
TextBox3.DataBindings.Clear()
TextBox4.DataBindings.Clear()
TextBox1.DataBindings.Add("text", bs, "nombre")
TextBox3.DataBindings.Add("text", bs, "comentarios")
TextBox4.DataBindings.Add("text", bs, "ruta")
End Sub
Private Sub
ConfigurarAdaptadorDatos()
Try
da = New
SqlDataAdapter("select
* from img", sql)
da.MissingSchemaAction = MissingSchemaAction.AddWithKey
Dim
cb As New SqlCommandBuilder(da)
cb.QuotePrefix = "["
cb.QuoteSuffix = "]"
da.InsertCommand =
cb.GetInsertCommand()
da.UpdateCommand =
cb.GetUpdateCommand()
da.DeleteCommand =
cb.GetDeleteCommand()
Catch
ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub Button2_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
Button2.Click
bs.MoveLast()
'Me.BindingContext(bs).Position
= Me.BindingContext(bs).Count - 1 aqui
no se necesita el bs
End Sub
Private Sub Button3_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
Button3.Click
If
bs.Position + 1 < bs.Count Then
bs.MoveNext()
End If
'Me.BindingContext(ds).Position
+= 1 aqui no se necesita el bs
End Sub
Private Sub Button4_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
Button4.Click
' Me.BindingContext(ds).Position -= 1 aqui no se necesita el bs
bs.MovePrevious()
End Sub
Private Sub Button1_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
Button1.Click
bs.MoveFirst()
'Me.BindingContext(ds).Position = 0 aqui no se necesita el bs
End Sub
Private Sub BNuevo_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
BNuevo.Click
bs.AddNew()
DataGridView1.Focus()
End Sub
Private Sub BGuardar_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
BGuardar.Click
Try
Me.Validate()
Me.bs.EndEdit()
Dim
n As Integer = Me.da.Update(Me.dt)
MessageBox.Show("Nº de
registros afectados: " & CStr(n))
Cargardatos()
Catch
ex As Exception
MessageBox.Show("Update failed")
End Try
End Sub
End
Class