17 de abril de 2012

SqlTransaction en VS

¿Qué pasa si en alguna en un procesos de actualización de datos de una base de datos falla a la mitad? Lo normal en la mayoría de los casos es deshacer todo lo que se ha hecho y dejar la base de datos como estaba. Este proceso sería muy complicado hacerlo a mano, por no decir imposible. Para esto están las transacciones, que de una manera muy fácil nos ayudan a resolver este tipo de problemas, sobre todo es util cuando hay varias tablas involucradas en los cambios a realizar, pues  las operaciones son indivisibles, lo que significa que o se ejecutan todas las operaciones o no se ejecuta ninguna. En el Caso de las Transacciones con las Bases de Datos, si la Transacción ha dado error se hace un “Rollback” para deshacer todos los cambios.

Aquí ingresaremos datos a una tabla llamada personal dentro de una base de datos llamada empleado, lo primero que hacemos es crear una cadena de conexión y abrir una conexión con ésta. Con esta conexión abierta creamos la transacción (con el método “BeginTransaction”) y ejecutamos la instrucción de insertar datos. Si todo ha ido bien, hacemos un “Commit” de la transacción y si algo ha fallado hacemos un “Rollback”. Es importante hacer un ”Commit” ya que si no, el sistema hará un “Rollback” automáticamente al cerrar la conexión.

este es el diseño del formulario a utilizar tanto en VB como en C#, se usara también un procedimiento almacenado llamado InsertarDatos para guardar los registros en la base de datos



Ejemplo Transacciones en VB

Imports System.Data

Imports System.Data.SqlClient
Imports System.Configuration

Public Class Control
    Dim trans As SqlTransaction = Nothing
    Private Sub BAgregar_Click(sender As System.Object, e As System.EventArgs) Handles BAgregar.Click

        Try
            Using Sql As New SqlConnection(My.Settings.cnn)
                Sql.Open()
                trans = Sql.BeginTransaction(IsolationLevel.ReadCommitted)
                Using cmd As New SqlCommand("InsertarDatos", Sql, trans)
                    cmd.Connection = Sql
                    cmd.CommandType = CommandType.StoredProcedure
                    cmd.Parameters.AddWithValue("@codigo", TNombres.Text)
                    cmd.Parameters.AddWithValue("@nombres", TApellido.Text)
                    cmd.Parameters.AddWithValue("@cargo", TPuesto.Text)
                    cmd.Parameters.AddWithValue("@jefe", TSueldo.Text)
                    cmd.ExecuteNonQuery()
                    trans.Commit()
                End Using
            End Using
        Catch ex As SqlException
            If Not trans Is Nothing Then
                trans.Rollback() 
            End If
            MessageBox.Show(ex.Message)
        End Try
    End Sub
End Class




Ejemplo Transacciones en C#


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.Data.SqlClient;

namespace WindowsFormsApplication11
{
    public partial class Form1 : Form
    {
        SqlTransaction trans;
        SqlConnection sql = new SqlConnection(ConfigurationManager.ConnectionStrings["cnn"].ConnectionString);
        SqlCommand cmd;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void BAgregar_Click(object sender, EventArgs e)
        {
            try
            {
                using (sql)
                {
                    sql.Open();
                    trans = sql.BeginTransaction(IsolationLevel.ReadCommitted);
                    using (cmd = new SqlCommand("InsertarDatos", sql, trans))
                    {
                        cmd.CommandType = System.Data.CommandType.StoredProcedure;
                        cmd.Parameters.AddWithValue("@nombre", TNombres.Text);
                        cmd.Parameters.AddWithValue("@apellido", TApellidos.Text);
                        cmd.Parameters.AddWithValue("@puesto", TPuesto.Text);
                        cmd.Parameters.AddWithValue("@sueldo", TSueldo.Text);
                        cmd.ExecuteNonQuery();
                        trans.Commit();
                    }

                }
            }
            catch (Exception ex){
                trans.Rollback();
                MessageBox.Show(ex.Message);
            }
        }
    }
}



 Cómo hemos visto el uso de transacciones desde .NET es muy fácil y hace nuestras aplicaciones más robustas. Pero, ¿qué pasa cuando entran en juego varias bases de datos, o incluso varios gestores de base de datos (varios Sql Server)? Para eso tenemos el TransactionScope, que podemos ver en http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

SqlConnectionStringBuilder en VS

Lo más correcto a la hora de leer una cadena de conexión a base de datos es almacenarla en un archivo .config y leerla desde allí, tal como se muestra en   http://pabletoreto.blogspot.com/2012/04/appconfig-en-vs.html

No obstante si no queremos leerla desde el archivo .config existe una forma más comoda de generarla mediante la clase SqlConnectionStringBuilder, SqlConnectionStringBuilder es una clase que nos permite crear conexiones ADO.net sin correr riesgos al introducir los valores, algunas de sus propiedades más importantes son:

DataSource: Establece u obtiene el nombre o la dirección IP de la instancia SQL Server a la que se conecta.
InitalCatalog: Establece u obtiene el nombre de la base de datos asociada con la conexión.
Integrated Security: Establece u obtiene el valor que indica el tipo de conexión. True para la seguridad integrada de windows, y False para indicar usuario y contraseña.
Password: Establece u obtiene la contraseña para la cuenta de SQL Server asociada a la conexión.
UserId: El usuario de SQL Server asociado a la conexión.
ConnectionString: Establece u obtiene el valor completo de la cadena de conexión, asociada al DBConnectionStringBuilder.

y estas son propiedades igual de importantes pero complementarias:

ApplicationName: Establece u obtiene el nombre de la aplicación asociada con el connection String
AsynchronousProcessing: Establece u obtiene el valor que indica si la conexión permite procesamiento asíncrono.
AttachDBFilename: Establece u obtiene el valor del datafile primario (.mdf).
BrowsableConnectionString: Establece u obtiene un valor que indica si la conexión es visible en el diseñador de Visual Studio.
ConnectTimeout: Establece u obtiene el timeout para la conexión.
Encrypt: Establece u obtiene un valor boolean que indica cuando SQL Server utiliza SSL encryption para todos los datos que se envían entre el cliente y el servidor.
MaxPoolSize: Obtiene o Establece el máximo número de conexiones en el connection pool.
MinPoolSize: Obtiene o establece el mínimo número de conexiones para el connection pool.
MultipleActiveResultsets: Obtiene o establece mediante un valor boolean el uso de MARS.
PacketSize: Obtiene o establece el número en bytes del paquete de red de intercambio de datos con SQL Server.
Pooling: Establece u obtiene un valor boolano que indica si se utiilza pooling.



SqlConnectionStringBuilder en VB

El diseño del formulario de la aplicación es solo un DatagridView que se cargara con datos de una base llamada empleados sobre una tabla llamada personal.



Imports System.Data
Imports System.Data.SqlClient
Public Class Form1
    Dim conn As New SqlConnectionStringBuilder

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        With conn
            .DataSource = "USER-PC\PABLETORETO"
            .InitialCatalog = "empleado"
            .IntegratedSecurity = True
        End With

        Try
            Using con As New SqlConnection(conn.ConnectionString)
                con.Open()
                Using sqlad As New SqlDataAdapter("select * from personal", con)
                    Using dt As New DataTable
                        sqlad.Fill(dt)
                        DataGridView1.DataSource = dt
                    End Using
                End Using
            End Using
        Catch
        End Try
    End Sub
End Class

en caso necesitar especificar usuario y password: conn.UserID = pUserId
conn.Password = pPassword 


SqlConnectionStringBuilder en C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.SqlClient; namespace WindowsFormsApplication1 { public partial class Form1 : Form{ public Form1(){ InitializeComponent(); } SqlConnectionStringBuilder conn = new SqlConnectionStringBuilder(); SqlConnection cnn; SqlDataAdapter sqlda; DataTable dt; private void Form1_Load(object sender, EventArgs e){ conn.DataSource = "USER-PC\\PABLETORETO"; conn.InitialCatalog = "empleado"; conn.IntegratedSecurity = true; using(cnn = new SqlConnection(conn.ConnectionString)){ cnn.Open(); using(sqlda = new SqlDataAdapter("select * from personal", cnn)) { using(dt = new DataTable()){ sqlda.Fill(dt); dataGridView1.DataSource = dt; }}} }}} en caso necesitar especificar usuario y password:
conn.UserID = pUserId;
conn.Password = pPassword;


 

13 de abril de 2012

App.config en VS

Al utilizar un app.config para configurar la cadena de conexión a la base de datos la principal ventaja que tiene es que evitaras tener que recompilar tu aplicación si es que vas a cambiar algun dato de la cadena de conexión, Ademas tambien esta la facilidad de modificarlos pues si en cada formulario usas la cadena de conexion, y un dia debes cambiar algo, tendrias que entrar a cada form y cambiar el valor, mientras que en el app.config o bien web.config solo lo cambias una vez y esta listo, claro que usar una clase para guardar los datos de conexion no esta nada mal, pero igual, por lo menos en los lugares que he trabajado utilizan el app.config para guardar los datos de configuración, tu valoraras por tu cuenta la utilidad de este.

ahora para guardar la cadena de conexión en un app.config ya sea en Vb o C# se siguen estos pasos, creamos un nuevo proyecto sea en VB o C# y luego desde el Solution Explorer damos click derecho sobre la aplicación que hemos creado y seleccionamos propiedades




luego nos vamos a la parte de Settings, colocamos un nombre y cambiamos el Type que por defecto tiene el valor de String por Connection string, luego damos click sobre Value en el pequeño botón examinar que aparece al final







después aparece esta ventana para seleccionar el servidor y la base de datos a utilizar, al especificar estos datos damos click en aceptar y luego guardamos, después podemos cerrar la ventana de propiedades





Luego debemos añadir una referencia al proyecto, para esto click derecho sobre la aplicación y luego Add Reference y sobre la pestaña .NET seleccionamos System.Configuration tal como se muestra








ahora, el nombre que yo use para la conexion a la base de datos es: conexion,  hago las pruebas desde mi maquina, me conecto a la base de datos empleado, asi pues el app.config en VB queda tal como se muestra:



y en C# el app.config queda asi:


Ahora se creara una interfaz para navegar a través de los valores de una tabla especifica en nuestra base de datos, ademas que se agregara un DataGridView, BindingNavigator y un textBox para cada dato de nuestra tabla, dicha interfaz de la aplicacion ya sea en VB o C# quedará de la siguiente manera:






App.config en VB


La ventana de la aplicación ejecutandose se muestra a continuacion, el nombre de mi cadena de conexion es "conexion", sabiendo esto, se dan las opciones de utilizar:

Dim cnn As SqlConnection

directamente al ConnectionString
Using cnn = New SqlConnection(ConfigurationManager.ConnectionStrings("conexion").ConnectionString)

my.settings del app.config (solo para VB):
Using cnn = New SqlConnection(My.Settings.conexion)

un modulo (solo para VB)
Using cnn = New SqlConnection(connex) 'conecta con valores desde el modulo los que recupera desde el app.config


una clase
Using cnn = New SqlConnection(k.conexx) 'conecta con valores desde la clase los que recupera desde el app.config

si eres de los que copian y pega código, las opciones aparecen comentariadas con su indicación a la que vez que se entrega al final el código del modulo y de la clase para que funcionen las opciones que te presento, recuérdese solo seleccionar una e importar el system.configuration



Imports System.Data
Imports System.Data.SqlClient
Imports System.Configuration
Public Class Form1
    Dim cnn As SqlConnection
    Dim da As SqlDataAdapter
    Dim dt As DataTable
    Dim bs As New BindingSource
    Dim k As New Class1  'necesario al utilizar la clase para conectarse
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Using cnn = New SqlConnection(ConfigurationManager.ConnectionStrings("conexion").ConnectionString)  
            'Using cnn = New SqlConnection(My.Settings.conexion)  'conecta usando setings del app.config
            'Using cnn = New SqlConnection(connex) 'conecta con valores desde el modulo los que recypera desde el app.config
            'Using cnn = New SqlConnection(k.conexx) 'conecta con valores desde la clase los que recypera desde el app.config
            Using da = New SqlDataAdapter("select * from personal", cnn)
                Using dt = New DataTable
                    da.Fill(dt)
                    bs.DataSource = dt
                    DataGridView1.DataSource = bs
                    BindingNavigator1.BindingSource = bs
                    TextBox1.DataBindings.Add("text", bs, "codigo")
                    TextBox2.DataBindings.Add("text", bs, "nombre")
                    TextBox3.DataBindings.Add("text", bs, "apellido")
                    TextBox4.DataBindings.Add("text", bs, "puesto")
                    TextBox5.DataBindings.Add("text", bs, "sueldo")
                End Using
            End Using
        End Using
    End Sub
End Class



El codigo del modulo es:

Imports System.Data.SqlClient
Imports System.Configuration
Module Module1
    'Public connex As String = My.Settings.conexion  'utilizando My.Settings
    Public connex As String = ConfigurationManager.ConnectionStrings("conexion").ConnectionString.ToString
End Module




El codigo de la clase es:



Imports System.Data.SqlClient
Imports System.Configuration

Public Class Class1
    '    Public conexx As String = My.Settings.conexion  'Utilizando My.Settings
    Public conexx As String = ConfigurationManager.ConnectionStrings("conexion").ConnectionString.ToString
End Class



--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



App.config en C#

Aquí no esta la opcion del modulo ni la de My.Settings como en VB, asi que solo presento como alternativa el utilizar una clase, de nuevo la ventana de la aplicacion ejecutandose y el codigo tanto del formulario principal como de la clase que se utiliza como una opcion alternativa se muestra a continuacion


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Configuration;

namespace AppconfigenC
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        SqlDataAdapter da;
        DataTable dt;
        SqlConnection cnn;
       //Class1 k= new Class1();    necesario para utilizar informacion desde la clase
        string conex = ConfigurationManager.ConnectionStrings["conexion"].ConnectionString;
        string select = "select * from personal";

                   
        private void Form1_Load(object sender, EventArgs e)
        {
            BindingSource bs;
           using (cnn = new SqlConnection(conex))
           //using (cnn = new SqlConnection(k.cnn))  este utiliza a cnn en la clase Class1
            {
                cnn.Open();
                da = new SqlDataAdapter(select, conex);
                dt = new DataTable();
                da.Fill(dt);
                bs = new BindingSource();
                bs.DataSource = dt;
                bindingNavigator1.BindingSource = bs;
                dataGridView1.DataSource = bs;
                textBox1.DataBindings.Add("text", bs, "codigo");
                textBox2.DataBindings.Add("text", bs, "nombre");
                textBox3.DataBindings.Add("text", bs, "apellido");
                textBox4.DataBindings.Add("text", bs, "puesto");
                textBox5.DataBindings.Add("text", bs, "sueldo");
            }
        }
    }
}





El codigo de la clase es:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data.SqlClient;

namespace AppconfigenC
{
    class Class1
    {
       public string cnn = ConfigurationManager.ConnectionStrings["conexion"].ConnectionString.ToString();
    }
}










10 de abril de 2012

Llenar DGV desde arreglos con VS

Esta fue una tarea de la universidad, aquí se digitará la información en tres textbox y luego al presionar el botón de agregar datos estos aparecerán en el DatagridView, sin necesidad de guardarse en ninguna base de datos, a la vez que mostrara en una columna del DataGridView el total de la multiplicación de los valores numericos especificados en cantidadTxT y valorTxT, aquí el diseño:






El código en VB 





Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.GenerarColumnas()
    End Sub
    Private ArregloDGV(0 To 3) As DataGridViewColumn 'Arreglo que contendrá la definición de las columnas.

    Private Sub GenerarColumnas()
        ArregloDGV(0) = New DataGridViewTextBoxColumn()
        ArregloDGV(0).HeaderText = "Articulo"
        ArregloDGV(0).Name = "colDesc"
        ArregloDGV(0).Width = 210

        ArregloDGV(1) = New DataGridViewTextBoxColumn()
        ArregloDGV(1).HeaderText = "Cantidad"
        ArregloDGV(1).Name = "colCant"
        ArregloDGV(1).Width = 80

        ArregloDGV(2) = New DataGridViewTextBoxColumn()
        ArregloDGV(2).HeaderText = "$ Valor"
        ArregloDGV(2).Name = "colValor"
        ArregloDGV(2).Width = 80

        ArregloDGV(3) = New DataGridViewTextBoxColumn()
        ArregloDGV(3).HeaderText = "$ Total"
        ArregloDGV(3).Name = "colTotal"
        ArregloDGV(3).Width = 80

        DataGridView1.Columns.AddRange(ArregloDGV)
    End Sub

    Private Sub Agregar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Agregar.Click
        If NombreTxT.Text.Trim() <> String.Empty AndAlso _
           cantidadTxT.Text.Trim() <> String.Empty AndAlso _
           valorTxT.Text.Trim() <> String.Empty AndAlso _
           IsNumeric(cantidadTxT.Text.Trim()) AndAlso _
           IsNumeric(valorTxT.Text.Trim()) Then
            Dim total As Double = Val(cantidadTxT.Text.Trim()) * Val(valorTxT.Text.Trim())
            Dim arrDatos() As Object = {NombreTxT.Text.Trim(), Val(cantidadTxT.Text.Trim()), _
                                        valorTxT.Text.Trim(), total}

            DataGridView1.Rows.Add(arrDatos)
        End If
    End Sub
End Class






El código en C#



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private DataGridViewColumn[] ArregloDGV = new DataGridViewColumn[4];
        int cantidad =0;
int valor = 0;
        private void Form1_Load(object sender, EventArgs e)
        {
            this.GenerarColumnas();
        }

        private void GenerarColumnas()
        {
            ArregloDGV[0] = new DataGridViewTextBoxColumn();
            ArregloDGV[0].HeaderText = "Articulo";
            ArregloDGV[0].Name = "colDesc";
            ArregloDGV[0].Width = 210;

            ArregloDGV[1] = new DataGridViewTextBoxColumn();
            ArregloDGV[1].HeaderText = "Cantidad";
            ArregloDGV[1].Name = "colCant";
            ArregloDGV[1].Width = 80;

            ArregloDGV[2] = new DataGridViewTextBoxColumn();
            ArregloDGV[2].HeaderText = "$ Valor";
            ArregloDGV[2].Name = "colValor";
            ArregloDGV[2].Width = 80;

            ArregloDGV[3] = new DataGridViewTextBoxColumn();
            ArregloDGV[3].HeaderText = "$ Total";
            ArregloDGV[3].Name = "colTotal";
            ArregloDGV[3].Width = 80;

            dataGridView1.Columns.AddRange(ArregloDGV);
        }

        private void Agregar_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(NombreTxT.Text.Trim()) ||
       string.IsNullOrEmpty(cantidadTxT.Text.Trim()) ||
       string.IsNullOrEmpty(valorTxT.Text.Trim()) ||
       (!int.TryParse(cantidadTxT.Text.Trim(), out cantidad)) ||
       (!int.TryParse(valorTxT.Text.Trim(), out valor)))
{
       return;
}

double total = cantidad * valor;
                object[] arrDatos = {
                           NombreTxT.Text.Trim(),
                           Convert.ToInt32(cantidadTxT.Text.Trim()),
                           valorTxT.Text.Trim(),
                           total
                    };

                dataGridView1.Rows.Add(arrDatos);
            }
        }

   
    }