.NET Chronicles

Temas relacionados con el desarrollo de aplicaciones con .NET

Octavio Telis

Utilidades de Sql Server con ADO.NET – Diagnosticar y Reparar Tablas


Hola ¿Qué tal?…


Continuando con la serie de utilidades de Sql Server con ADO.NET, llega a escena una herramienta que nos proporcionará diagnósticos y reparaciones de nuestras tablas, utilizando el mismo DBCC (Database Command Console) de T-SQL, realizaremos un método en la clase que creamos en la publicación anterior llamada SqlUtilities.


Reparar y Diagnosticar las Tablas de una Base de Datos de SQL Server con T-SQL


Para el diagnóstico y reparación de las tablas de nuestra base de datos utilizaremos la instrucción DBCC CHECKTABLE, en la publicación anterior checamos los campos identity de una tabla, con la instrucción DBCC CHECKIDENT, el cual repara la congruencia de la semilla que da los números automáticamente a los campos Identity y además permite regenerar el contador en caso necesario. En esta ocasión nos vamos un poco más arriba y veremos cómo reparar y diagnosticar nuestras tablas, además de que generaremos un archivo de reporte de los resultados obtenidos. En este caso DBCC CHECKTABLE comprobará la integridad de todas las páginas y estructuras de las que se constituye una tabla o una vista indizada.


Primeramente veremos la instrucción de T-SQL, cómo se usa y los parámetros que ocupa. En el siguiente ejemplo muestro los usos de CHECKTABLE utilizando T-SQL.

— Resume el diagnóstico de la tabla
DBCC CHECKTABLE (‘Production.Product’)

— Intenta reparar la tabla con el riesgo de perder datos
DBCC CHECKTABLE (‘Production.Product’,REPAIR_ALLOW_DATA_LOSS)

— Repara la tabla sin el riesgo de perder datos
DBCC CHECKTABLE (‘Production.Product’,REPAIR_REBUILD)

La primera instrucción devuelve un mensaje como el siguiene:

DBCC results for ‘Production.Product’.
There are 504 rows in 13 pages for object “Production.Product”.
DBCC execution completed.
If DBCC printed error messages, contact your system administrator.

Es importante mencionar que las últimas dos instrucciones solo se pueden realizar con la base de datos en modo de usuario único (single user mode). Esto implica que habrá que tener cuidado del uso de estas instrucciones, ya que solo deben utilizarse cuando se sospecha que la tabla tiene fallas en su estructura.  Siempre será mejor restaurar la base de datos en caso de que el diagnóstico devuelva errores en la tabla, el uso de las opciones de reparación es solo en caso de que no se cuente con un respaldo, así que si las reparaciones se aplican correctamente, será recomendable realizar un respaldo de la base de datos inmediatamente después de quedar reparada la tabla. Esta utilería pretende ser para diagnóstico más que para usarla como reparación, sin embargo ampliaremos la funcionalidad para tener herramientas que nos sirvan en casos extremos.


Diagnosticar y Reparar una Tabla de una Base de Datos de SQL Server con ADO.NET


Una vez identificado el uso de las instrucciones de DBCC CHECKTABLE en T-SQL, podremos realizar los métodos para la ejecución de estas instrucciones.

Será muy simple la manera de programar el método de diagnóstico ya que es análogo a lo que hicimos en la primera publicación de esta serie. Veamos cómo queda:

VB.NET

Public Sub CheckTable(ByVal Table As String)
    ‘Se declaran la variables a utilizar
    Dim cmd As SqlCommand = New SqlCommand(“DBCC CHECKTABLE (@Table)”)

    ‘Se agregan el parámetro @Table para identificar la tabla
    cmd.Parameters.Add(“@Table”, _
            SqlDbType.VarChar, 150).Value = Table
    ‘Se asigna la conexión al command
    cmd.Connection = cnn
    ‘Se intentará la ejecución del código
    Try
        ‘Se abre la conexión
        cnn.Open()
        ‘Se ejecuta la instrucción
        cmd.ExecuteNonQuery()
    Catch ex As Exception
        ‘Se capturan los mensajes de error
        mMessages = ex.Message
    Finally
        ‘se cierra la conexión
        cnn.Close()
    End Try
End
Sub

C#

public void CheckTable(string Table)
{
    //Se declaran la variables a utilizar
    SqlCommand cmd =
        new SqlCommand(“DBCC CHECKTABLE (@Table)”);

    //Se agregan el parámetro @Table para identificar la tabla
    cmd.Parameters.Add(“@Table”,
        SqlDbType.VarChar, 150).Value = Table;
    //Se asigna la conexión al command
    cmd.Connection = cnn;

    //Se intentará la ejecución del código
    try
    {
        //Se abre la conexión
        cnn.Open();
        //Se ejecuta la instrucción
        cmd.ExecuteNonQuery();
    }
    catch (SqlException ex)
    {
        //Se capturan los mensajes de error
        messages = ex.Message;
    }
    finally
    {
        //se cierra la conexión
        cnn.Close();
    }
}

El otro método, el cual servirá para realizar la reparación dependerá primeramente de un enumerador que definiremos fuera de la clase SqlUtilities. Este enumerador servirá para enumerar  las opciones de reparación con las que se contará. Así pues, definamos el enumerador, el cual se muestra en el siguiente ejemplo:


VB.NET

Public Enum RepairOption
    REPAIR_ALLOW_DATA_LOSS
    REPAIR_REBUILD
End Enum

C#

public enum RepairOption
{
    REPAIR_ALLOW_DATA_LOSS,
    REPAIR_REBUILD
}

Este enumerador lo utilizaremos en la definición del método de reparación. Este método será una sobrecarga del que se expone más arriba. La definición será prácticamente la misma, solo tendrá un parámetro adicional del tipo RepairOption que es el enumerador que hemos definido. Este enumerador lo utilizaremos en una siguiente publicación.


En el siguiente ejemplo se muestra cómo queda el método de reparación:


VB.NET

Public Sub CheckTable(ByVal Table As String, _
                      ByVal RepairOption As RepairOption)
    ‘Se declaran la variables a utilizar
    Dim cmd As SqlCommand = _
        New SqlCommand(“DBCC CHECKTABLE (@Table , “ & _
                        RepairOption.ToString() & “)”)
    ‘Se agregan el parámetro @Table para identificar la tabla
    cmd.Parameters.Add(“@Table”, _
            SqlDbType.VarChar, 150).Value = Table
    ‘Se asigna la conexión al command
    cmd.Connection = cnn
    ‘Se intentará la ejecución del código
    Try
        ‘Se abre la conexión
        cnn.Open()
        ‘Se ejecuta la instrucción
        cmd.ExecuteNonQuery()
    Catch ex As Exception
        ‘Se capturan los mensajes de error
        mMessages = ex.Message
    Finally
        ‘se cierra la conexión
        cnn.Close()
    End Try
End
Sub

C#

public void CheckTable(string Table, RepairOption RepairOption)
{
    //Se declaran la variables a utilizar
    SqlCommand cmd =
        new SqlCommand(“DBCC CHECKTABLE (@Table, “ +
                        RepairOption.ToString() + “)”);
    //Se agregan el parámetro @Table para identificar la tabla
    cmd.Parameters.Add(“@Table”,
        SqlDbType.VarChar, 150).Value = Table;
    //Se asigna la conexión al command
    cmd.Connection = cnn;
    //Se intentará la ejecución del código
    try
    {
        //Se abre la conexión
        cnn.Open();
        //Se ejecuta la instrucción
        cmd.ExecuteNonQuery();
    }
    catch (SqlException ex)
    {
        //Se capturan los mensajes de error
        messages = ex.Message;
    }
    finally
    {
        //se cierra la conexión
        cnn.Close();
    }
}

Aquí debemos tener en cuenta dos aspectos, el primero es un “trucazo” para utilizar el parámetro RepairOption sin usar un switch (Select Case en VB.NET) y usar directamente el valor del enumerador en la cadena de consulta, por eso es necesario declarar el enumerador con sus miembros textualmente idénticos a los que se utilizan en T-SQL al pasar los parámetros de reparación. Se usa la variable del tipo RepairOption y se invoca el método ToString() con el que se obtiene el nombre del identificador del valor del enumerador. El segundo aspecto es que no podrémos utilizar este método directamente sin antes haber cambiado la opción de acceso de la base de datos a Single_User, lo cual motiva la siguiente publicación.


Utilización del Método


Bien, aquí están los ejemplos de dos posibles usos:


VB.NET


Uso para diagnóstico:

‘Declaramos nuestra variable del tipo SqlUtilties
Dim sqlUtil As SqlUtilities = _
    New SqlUtilities(“(LOCAL)”, “AdventureWorks”, “”, “”)

‘Ejecutamos el método de diagnóstico       
sqlUtil.CheckTable(“Production.Product”)

‘Mostramos el resultado obtenido
MessageBox.Show(sqlUtil.Messages, “Resultados”, MessageBoxButtons.OK)

Uso para reparación:

‘Declaramos nuestra variable del tipo SqlUtilties
Dim sqlUtil As SqlUtilities = _
    New SqlUtilities(“(LOCAL)”, “AdventureWorks”, “”, “”)

‘Para reparar necesitamos cambiar la opción
‘de la base de datos a Sigle User
sqlUtil.ChangeDbUserAccessOption(DBUserAccessOption.SINGLE_USER)

If sqlUtil.GetCurrentDbUserAccessOption().Trim() = “SINGLE_USER” Then
    ‘Ejecutamos el método de Reparación
    sqlUtil.CheckTable(“Production.Product”, _
                        RepairOption.REPAIR_REBUILD)
Else
    MessageBox.Show(“La base de datos debe estar en Single User”, _
                    “Resultados”, MessageBoxButtons.OK)
End If

‘Mostramos el resultado obtenido
MessageBox.Show(sqlUtil.Messages, “Resultados”, MessageBoxButtons.OK)
‘Regresamos la opción de la base de datos
‘MULTI_USER

C#

Uso para diagnóstico:

//Declaramos nuestra variable del tipo SqlUtilties
SqlUtilities sqlUtil =
    new SqlUtilities(“(LOCAL)”, “VentasWeb”, “”, “”);
//Ejecutamos el método de diagnóstico
sqlUtil.CheckTable(“Production.Product”);
//Mostramos el resultado obtenido
MessageBox.Show(sqlUtil.Messages);

Uso para reparación:

//Declaramos nuestra variable del tipo SqlUtilties
SqlUtilities sqlUtil =
    new SqlUtilities(“(LOCAL)”, “AdventureWorks”, “”, “”);
//Para reparar necesitamos cambiar la opción
//de la base de datos a Sigle User
sqlUtil.ChangeDbUserAccessOption(DBUserAccessOption.SINGLE_USER);
if (sqlUtil.GetCurrentDbUserAccessOption().Trim() == “SINGLE_USER”)
{
    //Ejecutamos el método de Reparación       
    sqlUtil.CheckTable(“Production.Product”,
                        RepairOption.REPAIR_REBUILD);
}
else
{
    MessageBox.Show(“La base de datos debe estar en Single User”,
                    “Resultados”, MessageBoxButtons.OK);
}
//Mostramos el resultado obtenido
MessageBox.Show(sqlUtil.Messages);


Conclusiones


Hemos visto varias cosas nuevas aquí, y algunas contradicciones. Sobre las contradicciones quiero comentarles que puede verse contradictorio en algunas líneas de código el uso de concatenación de instrucciones cuando en la publicación en la que hablo de parámetros sugiero sobre todo el uso de parámetros en lugar de la concatenación. Bueno, en el caso de Alter Table fue necesario ya que no se puede utilizar un parámetro para indicar el nombre de la base de datos, también utilicé la concatenación para indicar los parámetros de algunas instrucciones DBCC, bien, cómo es que esto es válido a pesar de todo. Primeramente, la inyección de SQL no es posible en este medio ya que el nombre de la base de datos se toma de las propiedades de la conexión, si el nombre viene más la conexión hacia la base de datos no es posible, por otra parte, los parámetros se toman de los nombres de miembros de un enumerador fijo, por esta razón podemos decir que la concatenación es segura.


Por otra parte es claro que esta utilidad es muy delicada, debemos tener en cuenta que antes que reparar una tabla, debemos tomar el diagnóstico, y si marca errores, siempre será mejor restaurar un respaldo de la base de datos que intentar corregir la tabla.


Referencias de la Publicación

Esta publicación forma parte de la Serie 2 de la colección Utilidades de SQL Server con ADO.NET

Indice de publicaciones que conforman la Serie II:


Serie II Parte I: Diagnosticar y Reparar Tablas de una Base de Datos (http://msmvps.com/blogs/otelis/archive/2007/06/22/utilidades-de-sql-server-con-ado-net-diagnosticar-y-reparar-tablas.aspx)


Serie II Parte II: Cambiar la opción de acceso de una base de datos (http://msmvps.com/blogs/otelis/archive/2007/07/02/utilidades-de-sql-server-con-ado-net-cambiar-la-opci-243-n-de-acceso-de-una-base-de-datos.aspx)


Serie II Parte III: Consultar la opción de acceso de una base de datos (http://msmvps.com/blogs/otelis/archive/2007/07/02/utilidades-de-sql-server-con-ado-net-consultar-la-opci-243-n-de-acceso-de-una-base-de-datos.aspx)


Referencias Adicionales


Con esto terminamos nuestro recorrido por esta utilidad, si tienes alguna duda o comentario no dudes en dejarme tus comentarios. Las referencias de este tema las pongo a continuación:

DBCC CHECKTABLE
http://msdn2.microsoft.com/en-us/library/ms174338.aspx

ALTER TABLE
http://msdn2.microsoft.com/en-us/library/ms190273.aspx

sys.databases
http://msdn2.microsoft.com/en-us/library/ms178534.aspx


La Clase SqlUtilities
http://msmvps.com/blogs/otelis/archive/2007/06/19/utilidades-de-sql-server-con-ado-net-regenerar-campos-identity.aspx


Bien, pues espero que sea de utilidad.


Saludos…


Octavio Telis

Leave a Reply

Your email address will not be published. Required fields are marked *


*

.NET Chronicles
  • Eventos del Teclado en WPF July 22, 2015
      Hola ¿qué tal? En esta ocasión como como continuidad a lo que previamente había escrito sobre los eventos del teclado en Windows Forms, haré un artículo sobre el uso de los eventos del teclado en WPF, así es en Windows Presentation Foundation. No es desconocido por muchos que el nuevo estándar de desarrollo de […]
  • Programación Orientada a Objetos (Introducción) May 14, 2014
    Hola qué tal… Aquí les dejo este video sobre la programación orientada a objetos, a manera de preámbulo a los siguientes videos, con las bases de la programación en C# y otra línea con algunas utilerías. Saludos… Octavio Telis
  • Capítulo piloto del la versión en video de .NET Chronicles May 6, 2014
    Hola qué tal??? Pues en esta ocasión estoy compartiendo con ustedes la liga de un video piloto, con el que pretendo comunicar un poco más sobre las tecnologías .NET y los lenguajes de Programación. En esta ocasión será con la presentación de C#, en un capitulo titulado “Te presento a C#”, espero que sea de […]
  • Validación de datos de entrada con enlace a datos en WPF May 27, 2012
    Tweet Hola, qué tal. Ya que he venido hablando del enlace a datos en WPF en las publicaciones anteriores, bien convendría considerar el uso del Binding para validar datos, hemos tocado ya algunos puntos necesarios para escribir esta funcionalidad. En las publicaciones anteriores vimos ya como enlazar los datos, además, cómo convertir los datos, ahora, […]
  • Uso de la propiedad Visibility con valores booleanos en WPF May 25, 2012
    Tweet    Hola que tal. En esta ocasión quiero compartir con ustedes una manera para utilizar la propiedad Visibility con un valor bool. Te preguntarás “¿Y qué sentido tiene eso?”, bien, el detalles está en que en ocasiones se requiere que la visibilidad de un control de la interfaz de usuario responda a un valor […]
  • Conversión de Valores con Enlace a Datos May 24, 2012
    Tweet     Hola que tal. En el diseño de aplicaciones con WPF tendremos muchas ventajas en cuanto a la interfaz de usuario se refiere, dado que es un modelo muy flexible, nos permite dar formato y estilo a la apariencia de la interfaz de usuario, logrando aplicaciones más agradables, vistosas y que mejoran por mucho […]
  • Mostrar archivos de imagen en WPF utilizando enlace a datos. May 23, 2012
    Tweet Holal Qué tal. Continuando con el ejemplo del post anterior (http://bit.ly/oh0m9k), referente al manejo de imágenes en WPF, ejemplificaremos el manejo de las imágenes de la misma manera pero, esta vez, utilizando enlace a datos y la clase Binding. Antes, tenemos que hablar un poco de lo que es el enlace a datos con […]
  • Mostrar archivos de imagen en WPF August 26, 2011
    Hola Qué Tal… En esta ocasión quiero comenzar una serie de artículos sobre el manejo de archivos de imágenes con .NET. En esta primera parte voy a tratar la manera de cargar un archivo de imagen en un contenedor de imagen, en este caso usaré WPF y el control Image que viene incluido en el […]
  • Comparar dos DataTables según sus DataRows August 23, 2011
    Hola que tal. En ocasiones es necesario comparar el contenido de dos DataTable para determinar qué registros (DataRow) están en una y en otra no. Supongamos tenemos dos DataTable; dt1 y dt2, ambas con el mismo esquema. La tabla dt2 contiene más registros que la taba dt1, por lo que deseamos saber qué registros de […]
  • Arquitectura – Definición de un Data Access Component (con un ejemplo) Parte 3 May 14, 2010
    Hola Qué Tal? En esta ocasión, no he dejado pasar tanto tiempo para terminar la trilogía del uso de Data Access Component con un ejemplo. Bien, pues en este artículo veremos el uso del componente ya creado, cómo extenderemos la funcionalidad del componente y cómo lo aplicamos en la interfaz de usuario. Primeramente, debemos crear […]