Wednesday, July 20, 2011

Nuevas plantillas para Moviles aquí en BlogSpot

Acabo de ver que esta plataforma de Blog ha puesto a nuestra disposición plantillas para dispositivos móviles: Excelente, y además con un look bastante limpio y de mi agrado.

Bienvenidas todas estas mejoras. A mis colegas les recomiendo que les den un vistazo pues cada vez son mas los que acceden a través de estos dispositivos. Basta con habilitarlas en las opciones.

LINQ to SQL. Tratamiento de Transacciones con TransactionScope (parte 3 final))


Aunque no fue mencionado, la variante primera de lograr transacciones también tenía un problema: No se admitían transacciones anidadas.
La clase TransactionScope viene a solucionar todos los problemas con transacciones, diseñada incluso para el caso que queramos, en medio de una transacción, ejecutar un bloque de código fuera de ella.  Genial!.

Su uso seria en un bloque similar al siguiente:

using (TransactionScope trans = new TransactionScope())
{
    //Operaciones

    trans.Complete();
}

Aquí se extrañaran de no ver algo parecido a un Rollback y un bloque de try..catch en el cual se llame: NO ES NECESARIO. Al utilizar el TransactionScope en un bloque using, el mismo sistema se encarga de deshacer todas las operaciones si al concluirlo no se ha llamado al método Complete().
Claro que un bloque try..catch será necesario para capturar excepciones pero no para llamar a un Rollback específicamente.
Este mecanismo está preparado para hacer transacciones sobre múltiples servidores a la vez, caso en el cual usa el servicio MSDTC de Windows como soporte.
No obstante, no todo es felicidad. Esta clase utiliza un mecanismo propio (por llamarlo de una forma más amigable) en caso que dentro de su bloque se utilice solo una conexión de datos o DataContext. Si se llegan a utilizar dos entonces hace uso del servicio MSDTC para gestionarlo lo que nos obligaría a instalarlo en las PC donde se use el sistema.
En Windows7 de 64 bit existen varios reportes de personas en Internet que no les corre por la ausencia del servicio y en mi caso lo viví en carne propia. Aunque la solución sería la instalación del servicio y listo a mí no me resultaba factible agregar un pre-requisito más a mi sistema así que ajuste el código fuente a que usara siempre una sola instancia del DataContext al menos mientras se estuviera dentro del contexto de la transacción (bloque using).
Hasta aquí lo relacionado a los problemas más relevantes que hemos tenido. Los beneficios han sido muchos más con el uso de LINQ to SQL. Solamente tendría algo importante que criticarle y es que el modelo creado no incluye un par de métodos WriteToXml y ReadFromXml como los tiene la tecnología de Ado.Net con el uso de los DataSet. No es que Linq to SQL no tenga mecanismo de exportar a Xml sino que es, por mucho, más complejo, aunque también ofrece buena flexibilidad.
Todo problema con LINQ to Sql que puedan reportar en este blog será bienvenido.

LINQ to SQL. La Cache, ¿una ventaja o un problema? (parte 2)


Haciendo un buen resumen creo que me ha traído más problemas que ventajas aun cuando las ventajas sean medio invisibles por su propia naturaleza. A lo mejor una consulta es menos eficiente sin el uso del Cache pero no lo vemos.
La cuestión es que LINQ se encarga de manipular lo que ya tiene en memoria y lo que trae de la BD ante una consulta y no nos deja muchas opciones al respecto. Aun cuando existe una propiedad supuestamente bajo la cual le podemos decir al DataContext de LINQ que no utilice el Cache pues solo es funcional para datos de solo lectura.
Realmente a mí me gustaría poder decirle: No uses el Cache, tráeme siempre datos frescos.
El problema es simple, veámoslo en una secuencia de acciones, en donde todas usan un mismo objeto DataContext: 
  1. La instancia1 de la aplicación lee la existencia de un producto X = 0. LINQ lo mantiene en Cache.
  2. La instancia2 también lo lee. X = 0. LINQ lo mantiene en Cache.
  3. La instancia1 consulta de  nuevo la existencia de X y le suma 2. X = 2.
  4. La instancia2 consulta de  nuevo la existencia de X y le suma 3. Aquí debería queda X = 3 pero no, resulta que es igual a 3.
 ¿Cuál es el problema?
Que en el paso 4 cuando la instamcia2 consulta el valor de la existencia del producto X el Cache le devuelve el valor 0, aun cuando ya la instancia1 lo ha modificado.
Cuando al DataContext le solicitan datos lo hace a través de su Cache. Si el registro (siguiendo como criterio la llave de la Entidad) ya existe en la Cache entonces no lo consulta desde la BD sino que lo retorna desde allí mismo. Si no existe (solo si no existe) en la Cache entonces lo trae de la BD.
Cuando trabajamos en ambiente web con ASP.Net, sumado a que casi siempre seguimos un patrón Singleton para el DataContext general de la aplicación, no trae problema alguno. Pero en aplicaciones concurrentes es un gran problema.
Una solución es utilizar un DataContext nuevo cada vez que necesitamos datos frescos pero eso desde el punto de vista de la misma lógica no es siempre posible pues necesitamos los datos que ya tenemos y que no estarían en el nuevo DataContext.
Otra solución que encontramos, que usamos un tiempo, y que ni siquiera publicaré porque no me gusta, es crear un mecanismo (un truco) de limpieza del Cache del DataContext que usaremos cuando lo necesitemos, por ejemplo, antes de efectuar el paso 4 de la secuencia de acciones. Con esto obligamos al DataContext a traer de la BD el valor actual.
Pero aquí es donde el desconocimiento nos juega una mala pasada pues existe en el DataContext un método para ello, aun cuando esté poco documentado: Refresh.
public void Refresh(
        RefreshMode mode,
        IEnumerable entities
)

Cuando necesitemos obtener una copia fresca de los datos, por ejemplo de la tabla de Inventarios, podemos usar una sentencia similar a la siguiente justo antes de hacer uso de ella:
dc.Refresh(RefreshMode.OverwriteCurrentValues, dc.Inventories);

var inv = dc.Inventories.Where(i => i.IdProduct == op.IdProduct && i.IdLocation == op.IdLocation).SingleOrDefault();

Ahora, aun cuando esto soluciona definitivamente el problema de obtener datos frescos de la BD nos produjo una seria de problemas, algunos “mágicos” y por ende se nos iban de control.
El primero de ellos es que con una tabla de Clientes de 800 mil registros, en la cual hacíamos una búsqueda elemental, el sistema se demoraba una eternidad. Increíblemente el proceso de Refrescado casi congelaba la aplicación y no me pregunten por qué? Porque no tengo respuestas. En este caso era más factible realizar la búsqueda sobre un DataContext nuevo que sobre el existente y la velocidad era la normal. 
El segundo problema más serio aun es que el Refresh nos generaba una excepción cuando lo usábamos en un entorno de Transacciones como el mencionado arriba (parte1 de este artículo). La excepción nos decía algo así como que la conexión o la transacción no coincidía, etc, etc. Nada, un bugs que busqué un par de veces y no encontré un motivo. 
En el proceso de búsqueda de soluciones encontré una biblioteca de .Net específica para el tratamiento de excepciones. Una clase destinada a tales efectos: TransactionScope, que trataremos en la tercera parte de este artículo.

LINQ to SQL. Problemas y errores comunes (parte 1)

Implementación de Transacciones

Para los que trabajamos con Visual Studio.Net y hemos venido siguiendo su desarrollo desde sus inicios la llegada de “LINQ to SQL” supuso un paso de avance en el trabajo con bases de datos en Sql Server. Pero la migración a esta tecnología no está exenta de problemas y errores que muchas veces cometemos por no leer a fondo sus peculiaridades o por falta de tiempo para hacerlo.

Este artículo está destinado a usuarios que ya conocen y trabajan con esta tecnología. No pretende ser ni mínimamente una guía para principiantes.

LINQ (sin SQL) es un lenguaje de consulta muy potente y su gran ventaja es que puede ser aplicado a simples listas en memoria aun cuando su origen no sea desde bases de datos.

Este uso sobre simples listas en memoria (LINQ to Object) fue el primero que le di a esta tecnología en un proyecto que realizábamos hace ya algún tiempo. Aquí fue donde aprendí (junto con mi equipo) la sintaxis de cada sentencia y sus equivalentes en expresiones Lambda que casi siempre usamos.

Después lo comenzamos a usar en proyectos de ASP.Net con problemas menores que poco a poco fuimos solucionando y nos llevó a ganar en experiencia.

Pero la propia naturaleza de los proyectos Webs (todo corre centralizadamente en el servidor, por lo general se trabaja con una entidad a la vez en cada página) nos hizo muy fácil trabajar con una tecnología que no habíamos leído en sus aspectos más profundos referidos a acceso concurrente a datos y tratamiento de transacciones.

El verdadero dolor de cabezo vino recientemente en una aplicación Desktop que debía tener corriendo varias instancias a la vez modificando y compartiendo datos comunes a todas. En específico se trataba de una clásica aplicación de Venta y Control de Inventario con varios Puntos de Ventas en paralelo.

Cuando leemos sobre LINQ enseguida nos llevamos la idea que es un modelo de Objetos en memoria que mapea la estructura de la BD, de la cual permanece desconectada, que implementa operaciones de manipulación de datos y que mantiene una Cache de datos para evitar el tráfico innecesario y manipular de forma eficiente las operaciones. Dichas operaciones corren en un ambiente implícito de transacciones. Todo eso es bonito pero lo que no es bonito es la interpretación y el entendimiento que hacemos de ello con lo que comienzan a surgir los problemas más serios.

Transacciones implícitas, no tan implícitas.

Transacciones implícitas se traduce en la vida real en que las operaciones que hagamos sobre una misma tabla o entidad se ejecutarán en una transacción (todo o nada) pero no se refiere para nada a que si hacemos operaciones sobre más de una Entidad a la vez y una de ellas falla en el intermedio del conjunto pues se deshagan todos los cambios desde el inicio.

Aquí es donde comenzamos a implementar la primera versión de un modelo de transacciones, como el siguiente:


public static class DataHelper
{
public static IDbTransaction BeginTransaction(AdminDataContext dataContext)
        {
            if (dataContext.Connection.State == ConnectionState.Closed)
            {
                dataContext.Connection.Open();
            }

            dataContext.Transaction = dataContext.Connection.BeginTransaction();

            return dataContext.Transaction;
        }

        public static void CommitTransaction(AdminDataContext dataContext)
        {
            if (dataContext.Transaction != null)
            {
                dataContext.Transaction.Commit();
            }
        }

        public static void RollbackTransaction(AdminDataContext dataContext)
        {
            if (dataContext.Transaction != null)
            {
                dataContext.Transaction.Rollback();
            }
        }
}


Su utilización es trivial en un bloque de código similar al siguiente:
protected DataContext dc = DataHelper.GetDataContext();

try
{
    using (DataHelper.BeginTransaction(dc))
    {
        //Operaciones en varias Entidades
        dc.Inventories.InsertOnSubmit(...);
        dc.Kardexes.InsertOnSubmit(...);

        dc.SubmitChanges();

        DataHelper.CommitTransaction(dc);
    }
}
catch (Exception ex)
{
    DataHelper.RollbackTransaction(dc);
}


Esto nos soluciona el primer y más importante problema pero aún nos quedan otros que fuimos detectando en el camino y que incluso nos hicieron cambiar el modelo de Transacciones, aun cuando este funciona.

PowerShell ¿Qué es?

Desde que comencé a utilizar SqlServer 2008 me llamó la atención que entre los requisitos de instalación existía algo llamado PowerShell al cual no le di la mayor importancia salvo un poco de Curiosidad. Pero en ese momento el tiempo no sobraba, asi que me dije: algún día veré que es?

Hoy, con media jornada de tiempo semi libre, pues he buscado y he encontrado un excelente artículo de un cólega del ramo el cuál explica en detalles y con ejemplo su importancia y utilidad.

Yo no voy a escribir sobre lo escrito y como estoy seguro que a mis amigos les resultará util conocerlo pues vale la perna remitirlo directamente a dicho blog.

Como incentivo les mencionaré que es una poderosa herramienta de comandos con la que podemos hacer cualquier tarea de administración sobre SqlServer sin necesidad de tener instalado el SqlServer Mangement Studio, situación que bien se nos puede dar en ocasiones sobre entornos de Clientes nuestros.

Les dejo con 2 enlaces, uno de inciación y otro más detallado y orientado a SqlServer en específico.

http://elpaladintecnologico.blogspot.com/2009/02/que-es-powershell-ejemplos-basicos-para.html


http://elpaladintecnologico.blogspot.com/2009/02/tutorial-de-powershell-para-sql-server.html