Implementación sencilla del ControlState

El ControlState es un mecanismo alternativo al ViewState para guardar el estado de sesión en un control de usuario. Como es bien conocido disponemos múltiples objectos para guardar variables de sesión, todos ellos con una utilización parecida (básicamente son colecciones clave-valor de tipo string-object), que nos permiten mantener el estado entre llamadas en distintos ámbitos. El ámbito del controlState es pareceido al ViewState, con la diferencia fundamental de que éste último puede desactivarse. Éste es el motivo por el cual datos críticos para el buen funcionamiento del control deberían de guardarse en el ControlState (Ver Artículo MSDN) . Esta semana he constatado que su especial funcionamiento constituye una barrera de entrada para su utilización en programadores poco iniciados. Por este motivo me he decidido a publicar este post, con un pequeño código que, insertado en nuestro control, hará posible la utilización del ControlState de forma análoga al objeto Cache, ViewState, Session, etc.

    protected Dictionary<string,object> ControlState;

 

    //Guarda el diccionario personalizado y lo que

    //tuviese que guardar en el método base

    protected override object SaveControlState()

    {

        return new Pair(base.SaveControlState(), ControlState);

    }

 

    //Recupera por separado el diccionario personalizado

    //y el objeto para el método original

    protected override void LoadControlState(object savedState)

    {

        if (savedState != null)

        {

            Pair par=(Pair)savedState;

            base.LoadControlState(par.First);

            if (par.Second != null)

            {

                ControlState = (Dictionary<string, Object>)par.Second;

            }

        }

       if(ControlState==null)

           ControlState=new Dictionary<string,object>();

    }

 

Y para que todo esto funcione solo nos resta añadir en el evento load de la página la siguiente línea:

        Page.RegisterRequiresControlState(this);

 

Puesta a cero de la base de datos en pre-producción

Tenemos nuestro nuevo proyecto preparado para el despliegue. Subimos nuestro sitio web al servidor de producción, ejecutamos el script de creación de la base de datos, configuramos la aplicación y vamos a probar y ….. no funciona grrrr#**&*!!!! ¡A cuántos nos sonará este tema! Lo cierto es que es posible ( e incluso probable) que con el cambio de entorno tengamos que hacer unos cuantos retoques en nuestra aplicación, realizar unas cuantas pruebas, etc. Despues de esto nuestra recién creada base de datos estará sucia y posiblemente queramos volver a inicializarla.

Por diversos motivos puede que no nos interese cargarnos la base de datos otra vez, con lo cual intentaremos unicamente borrar las tablas (puede que ni siquiera tengamos permisos para borrar la base y volverla a crear, de ahí el interes de este método). Podemos utilizar un procedimiento que recorra las tablas listadas en INFORMATION_SCHEMA.TABLES e vaya ejecutando un delete sobre ellas. Con este método únicamente borraremos parte de las tablas, ya que tenemos altas probabilidades de que muchas de las filas se queden bloqueadas por relaciones foreign key al ejecutar el barrido con un orden arbitrario (el de INFORMATION_SCHEMA.TABLES). Además tenemos el problema añadido de que los índices de las tablas no se reinicializan ya que debido otra vez a las foreign keys no podemos utilizar Truncate en lugar de Delete.

El código listado a continuación viene a solucinonar la problemática descrita, borrando todas las tablas de la base de datos independientemente de sus relaciones y reinicializando los índices a 0 en las tablas que dispongan de este tipo de campos. Nótese que el código hace incidencia especialmente en lo funcional, obviando consideraciones que nos distaigan del objetivo principal

            

            //Definimos la conexión a la base

            SqlConnection cn = new SqlConnection(«ConnectionString»);

            //Definimos un comando auxiliar

            SqlCommand aux = new SqlCommand(«», cn);

            //Por último un comando auxiliar que carga las tablas de la base de datos.

            SqlCommand select = new SqlCommand(@»select * from INFORMATION_SCHEMA.TABLES where TABLE_TYPE like ‘BASE TABLE'», cn);

            SqlDataAdapter selectDA = new SqlDataAdapter(select);

            DataTable tablas;

            selectDA.Fill(tablas = new DataTable());

            cn.Open();

            bool repetir;

            do

            {

                repetir=false;

                foreach (DataRow tabla in tablas.Rows)

                {//Borramos cada una de las tablas

                    aux.CommandText = «Delete « + tabla[«TABLE_NAME»].ToString();

                    try

                    {

                        aux.ExecuteNonQuery();

                    }

                    catch (SqlException ex)

                    {

                                               if(ex.Number==547) //Infracción de FK: hay que repetir el borrado

                            repetir=true;

                    }

                }

            } while (repetir);

            foreach (DataRow tabla in tablas.Rows)

            {                   

                aux.CommandText = «DBCC CHECKIDENT (« + tabla[«TABLE_NAME»] + «,RESEED,0)»;

                try

                {

                    aux.ExecuteNonQuery();

                }

                catch

                {}//No todas las tablas tienen columnas de identidad para regenerar

            }

            cn.Close();