Grimpi IT Blog

Noviembre 22, 2008

Patrones de Acceso a Datos: Active Record

Archivado en: .NET, Arquitectura, Capa de Datos, Patrones — Etiquetas:, — grimpi @ 10:12 pm

Existen varias estrategias, arquitecturas y patrones de diseño para el manejo de la lógica de negocio y el acceso a la base de datos.
Que determina el uso de una u otra arquitectura esta dado por la especificadores y características del software a desarrollar y también por el gusto de quien diseña el esqueleto de la aplicación (la subjetividad es un factor muy determinante en el desarrollo de software, muchas veces más que cualquier argumento racional).
Hoy vamos a ver uno de estos patrones: Active Record.
ActiveRecord es un patrón en el cual, el objeto contiene los datos que representan a un renglón (o registro) de nuestra tabla o vista, además de encapsular la lógica necesaria para acceder a la base de datos. De esta forma el acceso a datos se presenta de manera uniforma a través de la aplicación.
Lógica de Negocio + Acceso a Datos en una misma clase.
Una clase Active Record consiste en el conjunto de propiedades que representa las columnas de la tabla más los típicos métodos de acceso como las operaciones CRUD, búsqueda (Find), validaciones, y métodos de negocio.
Personalmente me gusta mucho este enfoque, es muy elegante y simple.

En que situaciones CONVIENE usar este patrón?

  • Lógica de negocio simple y poco relacionada con otras entidades.
  • Es ideal cuando la estructura de la tabla coincide con la estructura de la clase.

En que situaciones NO CONVIENE de Active Record:

  • Es simple. Esto es bueno y malo al mismo tiempo. Con lógica de negocio compleja, este patrón pierde coherencia.
  • Otra desventaja que al estar tan acoplado a la estructura de la clase, un cambio en el diseño de la tabla, implica cambiar la clase.
  • En situaciones de operaciones de alto volumen de datos, el overhead que se paga en el pasaje y carga de datos, es innecesario. Esta desventaja aplica tanto a Active Record, como a cualquier otro diseño orientado a objetos.
  • Muchos “puristas” de OOP critican que ActiveRecord tiene una misma clase tanto la responsabilidad de acceder a la base como de manejar la lógica de negocio y “ensucia” el código. Nunca coincidí con ese fundamentalismo que a veces prioriza el purismo por sobre la simplicidad, pero es algo que muchos critican de este patrón.

Ejemplo de una clase típica de Active Record:

public class Order
{

public Order()
{
}

public Order(int orderID)
{
}

public int OrderID {get; set;}
public DateTime OrderDate {get; set;}
public DateTime ShipDate {get; set;}
public string ShipName {get; set;}
public string ShipAddress {get; set;}
public string ShipCity {get; set;}
public string ShipCountry {get; set;}

public void Insert()
{
// Inserta un registro en la tabla
}

public void Delete()
{
// Elimina el registro de la tabla
}

public void Update()
{
// Modifica el registro en la tabla
}

public static int GetCount()
{
// Retorna el total de registros de la tabla
}

public static Order FindById(int id)
{
//Busca en la tabla el objeto usando como criterio su id.
}

public static List<Order> LoadAll()
{
// Carga todos los regisotros de la tabla.
}

}
Por lo general siempre existen algunos métodos estáticos, como por ejemplo LoadAll(), que devuelve una colección de objetos de la misma clase. Otro típico ejemplo de un método estático es el FindById()

Conversión de datos

Este es un problema habitual en cualquier metodología que haga un mapeo de datos de un objeto con la base de datos.
Por ejemplo, si tenemos en la tabla una columna de tipo int cuyo valor en un registro es nulo, como convertimos este valor dentro de una propiedad del objeto? Por un lado podemos usar Nullable<int> que viene a partir de .NET 2.0. Otra estrategia es transformar valores nulos en 0. Puede parecer un poco desprolija esta metodología, pero muchas veces hay que preguntarse si queremos identificar entre un campo numérico nulo y uno cuyo valor sea 0. Obviamente, si queremos poder distinguir entre estos 2 valores, deberemos usar Nullable<int>.

Foreign Key Mapping Pattern (FKM)

Supongamos con el ejemplo que vimos anteriormente, que la tabla Order, tiene una FK a la tabla Customer. Como se debe comportar una clase Active Record cuando la tabla con la que trabaja tiene una Foreing Key?
Existen 2 maneras:

En primer lugar, mantener lo mas purista y simple posible y agregar solamente una propiedad más que sea el CustomerId, de manera que la estructura del objeto sea idéntica a la estructura de la tabla.

public int CustomerID {get; set;}

La segunda opción, es usar el patron Foreign Key Mapper. En mi opinión, una opcion mucho mas clara mucho más clara que consiste en vez de agregar una propiedad que represente el ID de la tabla, agregar una propiedad que sea una referencia directa al objeto.

public Customer Customer {get; set;}

Row Data Gateway Pattern (RDG)

Row Data Gateway es un patrón exclusivamente orientado al acceso a la base de datos, pero de características similares a Active Record.
La gran diferencia entre ambos, es que Active Record incluye métodos de acceso a la base de datos y métodos de lógica de negocio, mientras que Row Data Gateway, solo incluye métodos de acceso a la base.

Frameworks y generadores de codigo

  • Castle ActiveRecord: Por lejos, el framework más común que para trabajar con Active Record en .NET. Esta implementado sobre nhibernate, por lo cual también hay que tener esta librería para poder usarlo.
  • LINQ to SQL: Es la solución desarrollada por Microsoft para el mapeo de objetos con la base de datos. Puede también usarse con el patrón Active Record.
  • Además de estos frameworks, existen herramientas de generación de código en base a este patrón como .netTiers. También uno se puede crear su propio template de generación de código con MyGeneration o CodeSmith.


Noviembre 12, 2008

Interop y cómo usar un componente .NET desde Visual Basic 6 y ASP

Archivado en: .NET, Interop — Etiquetas:, , — grimpi @ 2:22 am

La tecnología COM fue la solución de Microsoft para el desarrollo de componentes reutilizables que puedan funcionar de manera distribuida y que sean independientemente del lenguaje de programación.
Con el desarrollo de .NET, COM quedo relegado. Sin embargo, muchos sistemas actualmente en producción, especialmente los desarrollados en VB 6 y ASP legacy, siguen usando esta tecnología.
Dado que existe una plataforma de desarrollo mucho más robusta y potente como .NET, es posible crear componentes en esta tecnología y que puedan ser invocados desde una aplicación VB 6 o ASP? La respuesta es afirmativa.
Dentro del Framework .NET, existe una librería llamada Interop que permite tanto usar un componente COM desde .NET como permitir llamar un assembly desde una aplicación COM.

Hoy vamos a explicar esto último, cómo usar un componente desarrollado en .NET desde ASP legacy o Visual Basic 6. La idea no es entrar en profundidad en este tema ni todas sus desventajas, sino hacer una guía rápida para el desarrollo de componentes COM en .NET.

  • El primer paso es crear explícitamente interface POR CADA clase que queremos exportar a COM. Si no lo hacemos, el compilador lo va a hacer solo, con el riesgo de perder compatibilidad binaria. Para decirle al compilador que no genera una interface por cada clase a exportable, hay que poner en el archivo assembly esta sentencia:

[assembly: ClassInterface(ClassInterfaceType.None)]

  • Hay que indicar como queremos que se instancien las clases COM (Late binding o Early bindin o ambos). Si queremos que se puedan crear de las 2 maneras, en cada interfaz hay que poner el atributo:

    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)]

    Si solo queremos Late bindig hay que poner (recomendado)

    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDispatch)]

  • Las clases que no se desean exportar a COM deben tener el atributo ComVisible(false)
  • Se debe firmar el componente, ya sea usando el programa sn.exe –k o directamente desde la IDE (esto solo se puede con VS 2005/2008).
  • Una vez compilado, se debe usar el programa Gacutil.exe para poner el assembly en la GAC (mas info sobre la GAC aca) y regasm.exe para generar y registrar el TLB del assembly.
    Ejemplo:

regasm Nombre.dll /tlb: Nombre.tlb

gacutil /i Nombre.dll

Para deregistrar el componente, hay que ingresar

regasm /u Nombre.dll /tlb: Nombre.tlb

gacutil /u Nombre.dll

Lamentablemente por alguna razón, el instalador de Visual Studio 2005/2008 no viene con el regasm.exe, por lo cual para conseguirlo es necesario descargar todo el SDK de .NET (http://www.microsoft.com/downloads/details.aspx?FamilyID=fe6f2099-b7b4-4f47-a244-c96d69c35dec&displaylang=en).

  • Una vez registrada el tlb, podemos usarlo desde VB 6 como si fuera un típico componente COM tradicional.

Consideraciones y Restricciones:

  1. Los constructores con parámetros no se pueden exportar a COM.
  2. Cuando se pasa un parametro variant en ASP o VB6 a un metodo de .NET se debe pasar entre parentesis. Sino genera el error Invalid Procedure or call Argument.
    Ejemplo:
    call ClaseInstancia.MetodoNuevo((ParametroVariant),OtroParametro)
  3. No se pueden usar NullTypes ni Generics.
  4. El paso de .NET a COM, requiere de una capa intermedia (marshaling), que por supuesto tiene un costo de procesamiento, algo que hay que tener en cuenta en sitios con alta cantidad de usuarios.
  5. Interop debe ser entendido y usado como una solución de corto y mediano plazo, para facilitar la migración de un sistema VB 6/ASP legacy a la plataforma .NET, no como una práctica recomendable.

Mayo 3, 2008

Listar todos los ítems de un Enum vía reflection

Archivado en: .NET, Reflection — grimpi @ 2:59 am

Post simple y práctico, como listar todos los ítems de un Enum vía reflection:

public static IEnumerable GetEnumList()
{
    Type enum = typeof(T);
    Array enums = Enum.GetValues(enum);
    List enumValList = new List(enums.Length);
    foreach (int val in enumValArray)
    {
        enumValList.Add((T)Enum.Parse(enum, val.ToString()));
    }
    return enumValList;
}

public static class Program
{
    public enum ObjectType
    {
        Item1 = 1,
        Item2 = 2,
        Item3 = 3
    }

    static void Main()
    {
        foreach (ObjectType state in GetEnumList())
        {
	    System.Console.Out.WriteLine(GetEnumDescription(state));
        }
    }
}

Abril 9, 2008

El patrón DAO

Archivado en: .NET, Arquitectura, Patrones, SQL Server — grimpi @ 1:12 am

Yo no soy un fanático de implementar montón de patrones y capas a los sistemas. Hoy en día hay sistemas que para desarrollar una función, requieren escribir en hasta 7 archivos diferentes.
Muchas veces complica más las cosas de lo necesario.
Sin embargo, uno de los patrones en mi opinión “fundamentales” del desarrollo de software, es el DAO (Data Access Object).
El DAO maneja la conexión con la fuente de datos para obtener y almacenar datos.

El uso de este patrón ofrece varios beneficios para la persistencia de datos:
* Sirve para separar el acceso a datos de la lógica de negocio. Algo altamente recomendable en sistemas medianos o grandes, o que manejen lógica de negocio compleja.
* Encapsula la fuente de datos. Esto es especialmente beneficioso en sistemas con acceso a múltiples entradas.
* Oculta la API con la que se accede a los datos. Por ejemplo en .NET si usamos siempre OleDb y queremos cambiar al NHibernate.
* Centraliza Todos los Accesos a Datos en un Capa Independiente

Cuando trabajamos con DAO, trabajamos en un mundo donde desconectado, donde nuestros datos se deben persistir en objetos.
Por lo tanto, cuando nos piden realizar una operación, se abre la conexión a la base, se ejecuta el comando, si es una operación de lectura, se vuelca el contenido hacia una estructura de datos y se cierra la conexión.

Transacciones:
Un problema muy común cuando se trabaja con este patrón, es como usar las transacciones.
Se deben ejecutar todas las operaciones dentro de un método?
Puede un DAO invocar métodos en otro DAO? Quien y como se deben manejar las transacciones?
Bueno, todo esta problemática que define el límite de la transacción se llama “Transaction demarcation”.
Existen 2 modelos diferentes que aplican según la necesidad de la operación transaccional que se va a efectuar.
Uno hace al objeto DAO responsable de la transacción, el otro desplaza la transacción al objeto que esta llamando el método DAO.
El primer caso (y el más usual) se puede codificar de la siguiente manera en C#:

public class ProductoDAO
{
public void Eliminar()
{
SqlConnection connection = new SqlConnection(“CONEXION”));
conn.open();
using (SqlTransaction trans = new SqlTransaction(conn))
{
SqlCommand com = new SqlCommand(“DELETE FROM P1″, conn, trans);
com.Execute();
SqlCommand com2 = new SqlCommand(“DELETE FROM P2″, conn, trans);
com2.Execute();
SqlCommand com3 = new SqlCommand(“DELETE FROM P3″, conn, trans);
com3.Execute();
trans.Commit();
}

conn.close();
}

}

En este ejemplo, para eliminar todos los productos y tablas relacionadas, se llama al objeto que maneja las transacciones de ADO.NET.
Con lo cual es perfectamente lógico encapsular el borrado de todas las tablas en un mismo método DAO, ya que se está afectando solamente la entidad Producto.

Pero supongamos que queremos eliminar transaccionalmente además de todos los productos, todas las ventas y todas las agencias.
Seria correcto meter la lógica del borrado de Ventas y Agencias dentro del método EliminarProducto? Como funcionar, funcionaria obviamente, pero estaríamos mezclando operaciones de distintas entidades y peor aún, estaríamos agregando métodos poco reutilizables y confusos.
Entonces lo correcto en este caso sería meter la lógica de la transacción fuera del DAO.
Para poder implementar esto, es necesario usar Transacciones distribuidas que .NET se implementan con EnterpriseService (En Java existe JTA). En caso de que usemos SQL Server 2005, podemos simplificar su considerablemente.

public class Negocio

{
public static void EliminarTodo
{
using (TransactionScope scope = new TransactionScope())
{
VentasDAO.Eliminar();
AgenciasDAO.Eliminar();
ProductoDAO.Eliminar();
scope.Complete();
}
}
}

Pasaje entre capas:
Ahora bien, ya sabemos porque debemos usar DAO y que beneficios nos trae.
Pero como deben ser el pasaje de datos con esta capa? Qué tipo de estructura usar?
En .NET existen varias variantes:

1) Dataset (tipado o no tipado)
2) XML
3) Data Transfer Objects (o objetos de Entidad)

Dependiendo de las particularidades de la aplicación, una opción puede ser mejor que la otra.
Definitivamente en la mayoría de los casos, usar Dataset no es la mejor práctica. Estamos de acuerdo que tal vez sea la opción más “cómoda”, pero los dataset son objetos pesados y lentos (en comparación con un Datareader), tienen montón de información, propiedades y métodos que no necesitamos.
Pero lo peor no es eso, la principal desventaja es que fuerza a toda la aplicación a usar un objeto de una tecnología especifica.

La más común de todas, es usar los Data Transfer Objects (DTO), también conocido como Value Object (VO). Es el típico patrón asociado a DAO.
Que son los DTO? Bueno, no son más que simples objetos que solo tienen getters y setters, que sirven para transportar la información de una capa a otra. El usar este patrón, ganamos performance, ya que al ser objetos livianos ocupan menos memoria, además de que nos permite abstraernos de cualquier tecnología especifica.

Recomendaciones a la hora de implementar DAO:

1) Combinar con el patrón singleton:
Tiene sentido tener múltiples instancias de DAO en memoria?
En la mayoría de los casos no, por eso yo por lo menos, suelo declarar todas mis clases DAO como static.

2) Crear una interfaz y un factory:
Todos los DAO generalmente tienen métodos comunes a todos, como DeleteById, GetById, GetAll, etc.
Declarar una interfaz IDAO, nos permitiría hacer un factory de DAOs.

3) Evitar el uso de dataset:
Si, como dije antes, es cómodo usarlos, nos ahorran tiempo de desarrollo. Pero a un costo alto.

Links:
http://www.ibm.com/developerworks/java/library/j-dao/
http://www.miguelmatas.es/blog/2007/11/13/mejorando-nuestro-dao-y-dto/
http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.htm

Marzo 3, 2008

Add-In Property Generator para Visual Studio

Archivado en: .NET, Add-In ProperyGenerator — grimpi @ 2:46 am

En mis épocas de programador en Java, usaba el Eclipse. Este excelente IDE, tenía una opción de refactoring que se usa para generar todos los getters y setters de una clase a partir de las variables privadas declaradas en la misma. Lo que en Java se llama getters/setters, en C# o VB sería el equivalente a las propiedades de una clase.

Siempre extrañé esa funcionalidad en Visual Studio. Cuando tenemos clases de 15 o más propiedades, tomarse el trabajo de generar 1 x 1, es aburrido.

Por lo tanto señores, he decidido hacerme mi propio Add-in de refactoring para agregarle esta interesante opción al Visual Studio. Este Add-in que desarrollé es compatible tanto con el Visual Studio 2005 como 2008. He visto un viejo Add-in, que se llama VsPropertyGenerator, que hace más o menos lo mismo, pero no tiene soporte y a mí no me funcionó y además, el que desarrolle yo, considero que es más fácil de usar.

Es libre, gratuito, pueden copiarlo, piratearlo y más que nada, disfrutarlo. El link para bajarlo es el siguiente:

http://www.opendbdiff.com/Addins.rar

Las opciones para instarlo se encuentran dentro de un archivo .txt. Cualquier sugerencia, problema o duda, dejen un comentario aquí, que prometo contestar.

Febrero 26, 2008

Diferencias entre Union y Concat en C# 3.0

Archivado en: .NET, Linq — grimpi @ 2:11 pm

Ayer trabajando con C# 3.0 y LINQ, me tope con una duda. Cuál es la diferencia entre el método Concat y Union de la lista?

En definitiva, ambos métodos parecen ser muy similares. Agregan el contenido de una lista en otra. Sin embargo, hay una pequeña e importante diferencia. El método Concat, agrega todos los ítems de una lista, mientras que el Union, agrega todos los ítems de la lista que no están en la otra lista.

Para hacerlo más claro, si tuviéramos que hacer la traducción a lenguaje SQL, el Concat es el equivalente al UNION ALL, mientras que Union es equivalente a UNION. Esto se puede ver claro, si usamos Linq to SQL.

Veamos este ejemplo:

List<String> list = new List<string>();
List<String> list2 = new List<string>();
list.Add(“Hola”);
list.Add(“Manuela”);
list.Add(“Jose”);
list2.Add(“Hola”);
list2.Add(“Esteban”);
list2.Add(“Ricardo”);

List<string> query = list.Concat(list2).ToList();
query.ForEach(item => System.Console.WriteLine(item));

La salida en este ejemplo serian 6 registros, o sea, la suma de list + list2.
Pero veamos este ejemplo:

List<string> query = list.Union(list2).ToList();
query.ForEach(item => System.Console.WriteLine(item));

En este caso, la salida serian solo 5 registros. Porque? Porque el item “Hola” se encuentra en las 2 listas. Por lo cual, el método Union no considera el duplicado.

Blog de WordPress.com.