Cerrando temas…

abril 19, 2009 en Entrada Diario

Nada mas sensato que ir cerrando temas. Así que me he centrado en la actualización del blog, tanto en la parte de recuperar los elementos que ya existían como en algunos nuevos que tenemos disponibles ahora.

En estas últimas horas he vuelto a situar en la barra lateral por ejemplo, el traductor de Google, que permitía a las personas que visitan la pagina traducirla a otros idiomas fácilmente; el enlace a mi cuenta de contacto (correo y messenger), y las distintas listas que ya existían en la barra lateral, y que permitían acceder a las entradas bien ordenadas por categorías, bien a través de la enumeración de que exista al final de la barra lateral. Bueno… Y los dos banners que aparecen como muestra de solidaridad.

La nueva versión además ya incorpora lo que se llama “Nube de etiquetas”, tan de moda en estos días. Eso sí, me supone bastante trabajo repasar cada una de las entradas, una por una, e ir marcando las distintas etiquetas. Si eso se hace a medida que se escribe es una rutina mas. Si como ahora hay que volver a releer las entradas y extraer las palabras claves pues cuesta un “poquillo” mas… :-) Es un trabajo que tengo a medias por lo que no están todavía todas las entradas clasificadas. Y contamos tambien con una mejora adicional que es la existencia en este tema de un buscador de contenido, que antes no existía y que ahora permitirá buscar con mas precisión.

La versión de WordPress es la 2.71 y nos trae también muchas mejoras en el administrador del blog, así como en la gestión de contenido, tanto a nivel de interfaz como de usabilidad. No tiene nada que ver con la versión que estaba usando hasta estos días, en que me decidí a cambiarla.

Respecto a lo que falta… efectivamente falta todavía recuperar algunas cosas, a nivel de diseño del blog casi todas. Muchos logos o imagenes que ahora mismo no se como encajar. El espacio para los videos destacados tampoco tengo muy claro donde ponerlo. Las imagenes o avatares que acompañaban a las distintas categorias y que permitían identificar el tema central del articulo de forma visual y bastante eficaz y rápida. Y algún detalle menor que se que está por ahí pero que ahora mismo no me viene a la cabeza. Todo se andará con paciencia.

Tiempo al tiempo… ;-)

Actualizacion de WordPress

abril 17, 2009 en Entrada Diario

Esta noche, tras muchos días sopesando los pros y los contras, me he decidido finalmente a actualizar la versión del WordPress, consciente de que a pesar de que se presumía como una tarea sencilla, por cuanto es un proceso bastante automatizado, en la medida que había personalizado el tema, iba a encontrar algún problema. Y de hecho, así ha sido. :-(

Así que os pido perdón de antemano si han desaparecido algunas características que pudisteis encontrar utiles en la versión anterior. Y sobretodo que tengais paciencia. No parece existir una compatibilidad completa en cuanto al tema y he tenido que desactivarlo, ante las rupturas de codigo que se hacían visibles. No obstante, creo que va a ser un cambio positivo a medio plazo ya que me permitirá activar algunos plugins y widgets que pueden sernos utililes, y que no tenía disponible en la versión anterior.

Y ya para acabar, también quiero aprovechar esta entrada para compartir con vosotros un dato objetivo, y es que poco a poco crece el numero de personas que visita la página y que la lee. Es bajo si lo comparamos con otras, pero no es algo que me quite el sueño, ni es tampoco mi interés el que existan mas visitantes con un mero motivo de especular economicamente.
Segun el contador de Webstats hemos pasado de 4.121 paginas vistas en el año 2006, 12.011 en el año 2007, 16.686 en el año 2008 y en este que estamos, ya llevamos mas de 5.000 paginas vistas. Existe un enlace al final de la página por si os apetece verlo.
http://webstats.motigo.com/s?tab=1&link=2&id=2497982

Por curiosidad (y Parte III)

abril 8, 2009 en Ado Express & DataSnap, Advertencia, Artículos, ¿Sabías que...? [Delphi], Código, Consejo, Delphi, Entrada Diario

Nos habiamos quedado en la propiedad Delta…

Tanto la propiedad Data como Delta se definen como OleVariants, y se organizan internamente como un array de bytes, y es esta característica la que va a dotar de flexibilidad a las dos estructuras, que soportaran por un lado los datos, el contenido real, en el caso de la propiedad Data, y un registro de actualizaciones que representa a la propiedad Delta. Dicho registro, logicamente es de solo lectura, dado que es la unica forma de garantizar que es tan solo manipulable por el propio dataset. Tambien es por esa razón, ya que no nos es permitido modificarlo, es por la que existen metodos que nos permiten limpiar esa cache de datos que contiene los registros de cambios.

Pero lo mejor es que lo veamos con unos cambios. Lo primero que he hecho es modificar el navegador de articulos para que nos deje insertar, habiltando todas las opciones. Como solo vamos a poner nuestra atención en la tabla de articulos nos podemos olvidar de los detalles y del mecanismo para transmitir el valor a las claves ajenas desde la inserción del articulo. Sobre este punto, yo os volvería a remitir a los cursos de Ian Marteens, accesibles desde su web a un precio razonable. Esto con independencia de que podamos mas adelante comentar este punto. El framework que desarrolla Martens en cada capitulo de esos cursos aborda una buena cantidad de detalles necesarios para trabajar con el esquema DataSnap, tanto a dos como a mas capas.

Os propongo unos cambios en los datos de la tabla articulos. Los hago y vemos los resultados:

* Añadimos un registro a la tabla articulos.
  Articulo Descripcion
(Valor nuevo) A0006 Articulo 0006
* Modificamos el articulo con codigo A0005.
  Articulo Descripcion
(Valor anterior) A0005 Articulo 0005
(Valor nuevo) Art5 Otra descripcion
* Eliminamos tambien el artículo con codigo A0002.
  Articulo Descripcion
(Valor anterior) A0002 Articulo 0002

 
Ver delta

La rejilla inferior os muestra el contenido del registro de actualizaciones. La estructura es identica a nivel de campos, a la que contiene la propiedad Data, como ya hemos comentado. Pero en el delta, por cada registro existente en el data, pueden existir máximo un par de registros vinculados a éste. Segun el caso, ya que para las inserciones o los borrados tan solo necesitamos un registro y mantener en algun “sitio” algo que nos diga si es un borrado o una inserción (en ese punto interviene UpdateStatus con los valores [usModified, usInserted, usDeleted]). En el caso de las modificiones, el primero registro representa el contenido original y el segundo los nuevos valores que toma.

Si yo modificara repetidamente el registro correspondiente al articulo A0005, los cambios sobrescribirian repetidamente el segundo integrante del par, lo cual no es ni bueno ni malo, pero si es esclarecedor, si en algun momento piensas, al revertir los cambios, un comportamiento similar al de cualquier deshacer (ej Word en office) de las aplicaciones mas habituales.

Y retomando ya el motivo que originó estas tres entradas, ahora que ya estamos en contexto de poder razonarlo, parece dificil encontrar la forma de generar un metodo que de forma limpia y sencilla provoque el refresco de uno de los detalles cualquiera sin tener que liarse a crear nuevos conjuntos de datos auxiliares que invoquen en un segundo plano el contenido a importar. Quiero decir que no parece sencillo añadir un nuevo metodo o una nueva función que nos permita decirle:
- ¡Oye, majo!, que no quiero los detalles de la tabla composicion. Haga Vd el favor de mostrarme los valores correctos…

Y el problema en mi opinión (y como siempre digo es mi opinión y no tiene porque coincidir ni ser acertada) es el diseño en bloque de ambas cachés. Si tuviera que buscar una analogia quizás lo compararia a esas muñecas rusas que nunca sabes por el exterior cuantas van a contener salvo que las vayas abriendo de una en una hasta llegar hasta la que tu deseas.

Muñecas rusas

Nunca llueve a gusto de todos, decía mi padre. Así que me queda la pregunta si hubiera podido existir una alternativa que hubiera contemplado que estas cachés se hubieran repartido de forma equitativa a cada uno de los componentes ClientDataSet, dejando que cada palo hubiera aguantado su vela.

Ni idea… :-(

Por curiosidad (Parte II)

abril 7, 2009 en Ado Express & DataSnap, Advertencia, Artículos, ¿Sabías que...?, ¿Sabías que...? [Delphi], Código, Consejo, Delphi, Entrada Diario

Seguimos el experimento, intentado satisfacer nuestra curiosidad. :-)

Vamos a hacer lo siguiente:

* En el modulo de datos eliminamos los dos componentes TClientDataSet que contienen los detalles. Es decir, cdsComposicion y cdsComponentes desaparecen. Tambien eliminamos todos los campos persistentes del dataset maestro cdsArticulos Logicamente, una vez hecho esto, los dos componentes TDataSource ligados a los mismos (a cdsComposicion y a cdsComponentes) ahora han perdido las referencias a los dataset y apuntan a nil.

Cambio en el módulo de datos

* Vamos a añadir en el evento OnCreate del modulo principal un par de lineas para suplir las dos asignaciones perdidas.

procedure TMainTest.FormCreate(Sender: TObject);
begin
dsComposicion.DataSet:=
   TDataSetField(dsArticulos.DataSet.FieldByName('qComposicion')).NestedDataSet;

 dsComponentes.DataSet:=
   TDataSetField(dsComposicion.DataSet.FieldByName('qComponente')).NestedDataSet;
end;

El resultado: Todo sigue igual que estaba y podemos ver los datos en las rejillas de datos (tanto en el dataset maestro como en los detalles) porque la existencia de cdsComposicion y cdsComponentes parece meramente anecdótica.

Podeis verlo por vosotros mismos si lo ejecutais.

Segunda ejecución

Así que una de las primeras conclusiones o reflexiones al vuelo de estos comentarios es que nuestro dataset maestro (cdsArticulos) es el jefazo del grupo, nuestro hombre importante y el resto de detalles son tan solo una ventana a lo que se está cociendo en su interior. Son meros hombres de paja o si se prefiere, actores de relleno que hacen que el batallon de romanos tenga mas credibilidad. Lo cual no quiere decir para nada que se deban eliminar pues son una ayuda necesaria en la parte de diseño de nuestra desarrollo. Solo hablo de tomar conciencia de un detalle que nos puede pasar desapercibido, lo cual sí parece importante en el transfondo de la curiosidad que mueve este grupo de entradas.

La tercera parte tendrá que ver sobre el delta y de alguna forma, la reflexión casi cae por si misma, por su propio peso, si haceis cualquier modificación en uno de los registros, y tras el oportuno post, es pulsado el boton VerDelta. La asignación en:

procedure Tdatos.Verdelta;
begin
  try
    Delta.Data := cdsArticulos.Delta;
  except
    Delta.Data := Null;
  end;
end;

nos permitirá visualizar el esquema conceptual y fisico que usa nuestro proveedor de datos para generar las oportunas sentencias sql, es decir el registro de actualizaciones. Esa será nuestra tercera parada. Tambien de cuando en cuando hay que dormir… :-)

Por curiosidad (Parte I)

abril 6, 2009 en Ado Express & DataSnap, Advertencia, Artículos, Código, Consejo, Delphi, Entrada Diario

Por curiosidad, ya que hablamos de AdoExpres y Datasnap, vamos a perder unos minutos en un par de comentarios que me parecen interesantes y que me hicieron reflexionar durante varios días de la semana anterior. Como muchos de los comentarios que hemos compartido, han surgido a raiz del trabajo diario. En este caso, concretamente al modificar la ficha de Clientes.

Estaba frente al típico esquema maestro-detalle donde el maestro era la tabla de clientes y los detalles eran cualquier otra tabla relacionada con ésta a través de una clave ajena. Una de estas tablas, mostraba en un dbGrid las comisiones que habían generado las ventas a determinado cliente, y en el interior de la pestaña que contenia la rejilla, existía un botón para recalcularlas y corregir errores generados en la modificación de las facturas. Resumiendo un poco, el proceso iba a disparar un procedimiento en la base de datos cuya misión era recalcular las comisiones que se mostraban en la rejilla y, en principio, no iba a retornar un conjunto de datos sino unicamente el exito en la finalización o el codigo del error de existir éste. Esto era problematico en el sentido de que, dado que nuestro conjunto de datos se ubica en la cache local y el procedimiento es disparado en nuestro servidor, los valores visualizados por el usuario podian en determinados casos diferir de los reales tras la ejecución del proceso, y podríamos necesitar invalidar el contenido de aquel dataset para mostrar los nuevos datos.

Además, si estamos en esos momentos en el contexto de nuestra aplicación, será habitual que el usuario se encuentre frente a una ventana modal (la ficha del cliente) que actualiza los cambios tras “aceptar” (que finalmente cerrará la ventana modal y actualizará los cambios pendientes). Ese esquema que parece el mas habitual y funciona bien en la mayoría de los casos, nos pone en una tesitura un tanto peculiar y problemática. O bien obligamos a nuestro usuario a confirmar cambios cerrando la ventana modal para que visualice los nuevos datos, lo cual no deja de ser una pequeña chapuza. O bien, creamos un datasets auxiliar que nos permitirá importar los registros que han cambiado y que añadiremos a la cache local, bien actualizando los existentes, bien insertando si fueran nuevos. Esta ultima opción es trabajo extra que a nadie le apetece hacer, sobretodo si consideramos la enorme cantidad de tablas que se implican en una aplicación normal y corriente (las que se utilizan en los ejemplos de los libros no tienen parecido alguno con las del mundo real) :-)

En estos casos, lo habitual es acceder a Internet con el fin de comprobar si alguien ha tenido una inquietud similar y ha comentado algo al respecto. Y así lo hice. Y encontré casualmente un post en el foro del Club Delphi donde se comentaba este problema.

http://www.clubdelphi.com/foros/showthread.php?p=330090

En dicho post, participaba un programador de México, Al Gonzalez, que hace poco ha compartido algunos comentarios con nosotros, precisamente cuando hablabamos de Datasnap. El codigo final que se muestra en dicho post corrobora un poco lo comentado en las lineas anteriores.

Veamos un fragmento de dicho post:

procedure TForm1.Button12Click(Sender: TObject);
Var
  xClave:Integer;
begin
   //asegurase de que no existan pendientes
   //ya que MergeChangeLog lo eliminaria del Delta
    if ClientDataset3.ChangeCount>0 then
       showmessage('Hay datos pendientes en caché, aplicarlos antes del refresh')
    else begin
       //salvo el contenido del campo clave del registro a refrescar
       xClave:=ClientDataset3fcod_mast.AsInteger;
       //Leer de la Base de datos el registro a refrescar
       CDS_refresh.Close;
       CDS_refresh.Params.ParamByName('xClave').AsInteger:=xClave;
       CDS_refresh.Open;
       //borrar el registro que deseo refrescar
       ClientDataset3.Delete;
       //borrar datos de Delta
       ClientDataset3.MergeChangeLog;
       // añadir el registro - RefreshRecord
       ClientDataset3.AppendData (CDS_refresh.Data, True);
    end;
end;

Aparte de estos comentarios, y los que pude leer repasando los cursos de Marteens sobre [AdoExpress/DBExpress] y DataSnap (o bien lo escrito por el autor en las distintas versiones de “La cara oculta de…”), el resto de información no es demasiado abundante ni clara. Marteens es una excepción en ese escenario ya que no conozco todavía a nadie que le haya leido y que piense que la compra de ese libro o ese curso ha sido un gasto inutil. Todo lo contario. Un problema que tenemos, in eternis, es el de que resulta facil encontrar textos que describen nuestras herramientas pero que dificilmente nos enseñan a usarlas en el mundo real. En el simil del martillo, encontrariamos cien mil textos que nos explicarian el origen del martillo en la historia de la humanidad. Doble cantidad hablando de forma elocuente sobre las distintas formas del mango. Y contados escritos (se podrían contar con los dedos de la mano) explicando como clavar un clavo sin machacarse los dedos. :-)

Vamos a montarnos un pequeño ejemplo que nos permitirá experimentar y extrapolar el problema que hemos comentado. Imaginemos tres tablas, Articulos, Componentes y Composicion. Las relaciones entre ellas son muy sencillas. Lo mejor es verlo con una imagen.

Ejemplo

Es decir, la tabla Composición muestra una relación entre un articulo y los componentes de los que está compuesto.

Podéis descargar este zip que contiene el código fuente del ejemplo y un script para generar la base de datos en sqlserver:Fuente

Ejecutamos el programa y seguimos comentando. Esto nos muestra la ventana principal.

El primer comentario o duda que nos puede asaltar es preguntarnos si no es posible actualizar un registro detalle de un forma limpia y sencilla. Ejecutad la aplicación. Luego editad cualquier campo y confirmad con un post, (por ejemplo la descripción del componente en la ficha del componente y en lugar del texto “Componente 1″ poneis “Componente 1 modificado” o cualquier cosa que se os ocurra. Y finalmente, tras editar, pulsais el boton “Incrementa Cantidad” que ejecutará el procedimiento en el servidor que actualizará el campo cantidad en 10 unidades de cada uno de los componentes que forman parte de cada articulo. Es entonces cuando nos encontraremos el “problema”. Los registros de la tabla Composición han sido modificados por el usuario en un segundo plano pero el contenido de la rejilla no puede ser actualizado a menos que ejecutemos un ApplyUpdates. Solo entonces, es posible refrescar los datos.

Y no perdais de vista que nuestra ventana pueda ser modal, que puede ser una dificultad adicional con la que quizás tengamos que lidiar, por las razones comentadas al principio.

Vamos a hacer un pequeño alto en el camino, nos damos un pequeño respiro en este punto en el que ya tenemos planteada la inquietud. Os invito a seguir reflexionando sobre este tema en la siguiente entrada.