26 abr 2010

__doPostBack

ASP.Net 2.0. Me imagino que se habrán dado cuenta de que en las páginas de asp.net se implementa un curioso metodo llamado __doPostBack, de hecho nosotros lo podemos utilizar dentro de las funciones del lado del cliente de los controles de .Net como por ejemplo en el OnClientClick de un botón. Pero ¿que es lo que hace? y ¿cómo lo hace?

Básicamente realiza un submit de la página, ó sea, dispara el postback, como claramente indica su nombre. El método recibe dos parámetros: __EVENTTARGET y __EVENTARGUMENT El primero de los cuales recibe el nombre del control que dispara el postback y el segundo el método de dicho control.

Ahora, ¿cómo hace esta función para hacer el postback? El código que se genera automáticamente es mas o menos este:
< input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" / >
< input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" / >

function __doPostBack(eventTarget, eventArgument) 
{
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) 
    {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
Como se puede ver, son simplemente dos textbox ocultos y una función que los utiliza para el disparar el submit. Como lo dije antes, este código es generado automáticamente siempre y cuando haya al menos un control en la página que tenga al atributo “AutoPostBack” en True. Si lo queremos es usar la funcion sin que haya controles con el AutoPostBack en True, pues manualmente ponemos el código anterior en la página y listo.

Ahora bien, nosotros podemos hacen uso del método con los parámetros vacíos __doPostBack("",""); Esto dispara el submit y se hubiera algún método del lado del servidor que no se hayan ejecutado (por tener el AutoPostBack en False, por ejemplo) entonces ahora también se dispararán. Este método se usa en los treeview que no disponen de método de postback, cuando se utilizan con checkboxes, para que cuando hagan click en alguno de ellos se ejecute el método postback correspondiente.

Pero hay algo más. La realización de un simple Submit con controles ocultos significa que podemos capturar los valores de los parámetros(valores del los controles ocultos) del lado del servidor y por ende, ejecutar lo que nos parezca más conveniente en determinadas circunstancias. Así por ejemplo podemos hacer una función javascript como esta:
function MiPostBack ()
 {
     var o = window.event.srcElement;
     if ( o.tagName == "INPUT" && o.type == "checkbox")
     {                   
          __doPostBack("MiControl","MiEvento");
      } 
} 
La cual la podemos usar en el OnClick de un treeview para indicar de que si hace clic sobre un checkbox del treeview haga submit con estos parámetros. Y en el método Page_Load del lado del servidor tener algo similar a esto
string controlName = Request.Params.Get("__EVENTTARGET");
string controlEvent = Request.Params.Get("__EVENTARGUMENT");
if ((controlName=="MiControl")&&(controlEvent=="MiEvento"))
{
   UnMetodoCualquiera();
}
Así podemos ejecutar UnMetodoCualquiera(); cuando se produce un clic en alguno de los checkboxes del treeview (esto se realizó asi en un proyecto real para evitar que cuando se marcaba un checkbox padre se dispara el postback por cada hijo que también se marcaba automáticamente). Para mi esto abre más de una posibilidad para usar el __doPostBack cuando requiere ejecutar código del servidor.

16 abr 2010

Tablas temporales y cursores

Mi amigo Pigo Sama realizó un interesante articulo sobre tablas temporales y cursores.

Es interesante como señala la satanizacion de algunas de las características disponibles en motores de base de datos cuando, como bien lo indica Pigo, es cuestión de moderación y orientación en su uso.

4 mar 2010

Usar FOREACH ó SELECT

Hay veces en las que no nos detenemos a pensar, cómo estamos haciendo alguna tarea, simplemente no nos cuestionamos, tal vez porque estamos ajustados con los tiempos de entrega o peor aún, porque siempre lo hemos realizado así y no nos interesa preguntarnos si esaes la mejor forma. Debemos mantener la sana costumbre de preguntarnos cómo funcionan las cosas y si lo que hacemos es la mejor manera de alcanzar el objetivo.

Pues luego de esta introducción la pregunta: Tengo un DataTable y necesito encontrar una o varias filas según un criterio dado ¿Qué es mejor: recorrerlo con un foreach o hacer un select que me devuelva un arreglo de DataRows?.
Antes de contestar nada mejor lo probamos y salimos de las dudas. La prueba debe constar de lo siguiente:

- Crear el DataTable y Llenarlo con 2 millones de registros.
- Ejecutar un SELECT del DataTable, midiendo el tiempo que tarda.
- Ejecutar un FOREACH con el mismo criterio. Midiendo el tiempo que tarda

Paso 1 Creando el datatable y llenándolo de datos


/* Creamos el datatable con dos columnas*/
DataTable dt = new DataTable();
DataColumn dc1 = new DataColumn("Col1", System.Type.GetType("System.Int32"));
DataColumn dc2 = new DataColumn("Col2", System.Type.GetType("System.String"));
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);

/* Llenamos el datable con dos millones de registros*/
DataRow dr;
DateTime paso1 = DateTime.Now;
for (double i = 1; i < 2000001d; i++)
{
dr = dt.NewRow();
dr["Col1"] = i;
dr["Col2"] = "Datos de Prueba";
dt.Rows.Add(dr);
}
DateTime paso2 = DateTime.Now;
TimeSpan span = paso2.Subtract(paso1);
Console.WriteLine("total de Registros: " + dt.Rows.Count.ToString("N2"));
Console.WriteLine("Tiempo que dura la carga en milisegundos: " + span.TotalMilliseconds);


Paso 2 Setear la variable que vamos a usar la búsqueda y ejecutar el SELECT


/*Columna a encontrar*/
int var = 1234567;

/*Ejecutando el SELECT*/
paso1 = DateTime.Now;
DataRow[] arreglo = dt.Select("Col1 = " + var);
paso2 = DateTime.Now;
span = paso2.Subtract(paso1);
Console.WriteLine("Fin SELECT Total encontrados: " + arreglo.Length.ToString("N2"));
Console.WriteLine("Tiempo que duró el SELECT en Milisegundos: " + span.TotalMilliseconds);


Paso 3 Ejecutar el FOREACH


/* Ejecutando el FOREACH*/
ArrayList arraylist = new ArrayList();
paso1 = DateTime.Now;
foreach (DataRow dtr in dt.Rows)
{
if (Convert.ToDouble(dtr["Col1"]) == var)
{
arraylist.Add(dtr["Col1"]);
}
}
paso2 = DateTime.Now;
span = paso2.Subtract(paso1);
Console.WriteLine("Fin FOREACH Total encontrados: " + arraylist.Count.ToString("N2"));
Console.WriteLine("Tiempo que duró el FOREACH en milisegundos: " + span.TotalMilliseconds);


Esta es una prueba sencilla y hecha de forma apresurada, pero válida dentro de lo que necesitamos probar. El código está en una consola y está hecho en VS 2005 y en una maquina virtual con Windows 2003. El resultado de las pruebas fue el siguiente:


total de Registros: 2.000.000,00
Tiempo que dura la carga en milisegundos: 7000,0656
Fin SELECT Total encontrados: 1,00
Tiempo que duró el SELECT en milisegundos: 5638,1072
Fin FOREACH Total encontrados: 1,00
Tiempo que duró el FOREACH en milisegundos: 470,6768


Por lo que podemos ver la prueba arroja que la carga de dos millones de registros en la DataTable duro 7 segundos, ejecutar el SELECT 5 segundos y medio y el FOREACH menos de medio segundo. Se ejecutaron varias corridas y los resultados fueron muy similares. Triunfador sin discusión: el FOREACH.

Ahora, que pasa si al DataTable le ponemos una llave. Al poner una llave debemos tener en cuenta que el engine ADO.NET, debe indexar la tabla lo que se puede llevar a cabo durante la carga de información, cada vez que se añade una fila (si creamos la llave antes de carga la información) o al crear la llave si la creamos luego de la carga de datos. Para propósitos de la prueba lo coloqué después de la carga y antes de la variable de búsqueda para determinar claramente la penalización de tiempo por la indexación.


/*Creando LLAVE*/
paso1 = DateTime.Now;
DataColumn[] pk = new DataColumn[1];
pk[0] = dc1;
dt.PrimaryKey = pk;
paso2 = DateTime.Now;
span = paso2.Subtract(paso1);
Console.WriteLine("Creacion de llave en milisegundos: " + span.TotalMilliseconds);


Esta prueba arrojó el siguiente resultado


total de Registros: 2.000.000,00
Tiempo que dura la carga en milisegundos: 6789,7632
Creacion de llave en milisegundos: 5868,4384
Fin SELECT Total encontrados: 1,00
Tiempo que duró el SELECT en milisegundos: 10,0144
Fin FOREACH Total encontrados: 1,00
Tiempo que duró el FOREACH en milisegundos: 450,648


Después de varios ciclos de ejecución: el tiempo de carga se mantiene alrededor de los 7 segundos, la creación de la llave y por ende la indexación tarda entre 5.5 y 6 segundos. La ejecución del SELECT roza la instantaneidad y el FOREACH se mantiene en menos de medio segundo. Conclusión: el tiempo que tardaba la ejecución del SELECT se ha traslado a la indexación. Si hubiese más operaciones de búsqueda más adelante en el código sobre la misma datatable, puede que valiese la pena la creación de la llave pero de lo contrario prevalece la ejecución del FOREACH.

Finalmente hicimos unas pruebas utilizando un DataTableReader a partir del DataTable y recorriéndolo para obtener el mismo resultado, pero fue unas tres veces más lento que el FOREACH.

Muchas Gracias Jason y Pigo sama,

12 feb 2010

Track Item in Solution

Hay algunas cosas, detalles, que nos hacen la vida mas fácil. Esta es una de ellas. Visual Studio trae la característica que en el Solution Explorer resalta el archivo en el que estamos trabajando. Cuando las soluciones son grandes es especialmente útil.

Si alguna vez esta opción no parece habilitada, se puede rehabilitar en Tools -> Options Estando en Options, en el árbol de la izquierda escogemos Projects and Solutions -> General y ahí marcamos el check Track Active Item in Solution Explorer.


Muy útil!

26 ene 2010

Uso de palabra INTERFAZ

Hace algun tiempo un administrador de proyectos que tenia le conuslto a Don Fernando Diez, Filólogo del periodico LA NACION sobre el uso de la palabra interfaz. He aqui su respuesta:

INTERFAZ.

La voz inglesa interface, que significa, en informática, ‘conexión física y funcional entre dos aparatos o sistemas independientes’, se ha adaptado al español en la forma INTERFAZ: «Su interfaz gráfica y capacidades de acceso a Internet facilitarán aún más el uso del PC» (Vanguardia [Esp.] 30.8.95).

Su plural es INTERFACES (→ plural, 1g). Aunque no es infrecuente su uso en masculino, debe emplearse en FEMENINO, ya que esta palabra incluye en su forma el sustantivo femenino FAZ.

Con este sentido, NO debe usarse la forma interfase, que no responde ni a la pronunciación ni a la estructura semántica del étimo inglés, que se ha formado con el sustantivo face, cuyo equivalente español es FAZ, no fase. Tampoco se aconseja usar con este significado el término interficie.


Aparte les dejo un par de definiciones de la RAE con respecto a este tema:

interfaz:

(Del ingl. interface, superficie de contacto).

1. f. Inform. Conexión física y funcional entre dos aparatos o sistemas independientes.


interfase:


1. f. Biol. Período del ciclo celular en el que tiene lugar la síntesis de proteínas y la replicación del material genético.

2. f. Fís. y Quím. Superficie de separación entre dos fases.


Así que, como ven, esta claro: únicamente debe usarse interfaz e interfaces en nuestros quehaceres informáticos.