9.03.2010

DataSets o POCOs – Plain Old CLR Object

Al día de hoy no había querido ahondar en este tema porque es un tema un poco dificil de aclarar sin estar presente y sin la posibilidad de “hacer garabatos” en una pizarra para aclarar más las cosas; sin embargo, dado que el tema se repite una y otra vez, voy a tratar de explicar cuales son las razones por las cuales yo siempre prefiero utilizar POCOs a DataSets en este post.

Definiciones

En primera instancia, vamos a definir un POCO. Un POCO es un Plain Old CLR Object – un concepto traido desde Java desde el famoso POJO ( como muchos otros ) – y en el cual simplemente se define una clase que contiene los atributos de las entidades y sus propiedades. Además, la clase contiene un constructor vacío y un constructor para inicializar todos sus elementos.

El DataSet, como ya muchos saben es una clase bastante sofisticada que se encuentra definida en el namespace System.Data y es neutral al repositorio de datos que se este utilizando; – igual que el POCO – esta es la razón por la cual el DataSet esta definido en este Namespace. El DataSet es un contenedor que tiene la capacidad de mantener datos en memoria y de forma desconectada ( sin necesidad de tener una conexión a la base datos viva ) por lo que son útiles en algunos contextos donde se desea seguir trabajando si la base de datos no esta disponible – posible pero arriesgado.

Mi Opción

Yo siempre voy a preferir trabajar con POCO o entidades de negocios planas a trabajar con dataset por las razones que a continuación enumero:

  1. El costo de instanciación de un dataset vrs un POCO es muy alto. El dataset tiene una cantidad enorme de relaciones con clases que le permiten llevar a cabo todas sus tareas cuando se necesita. Por ejemplo, hay colecciones que se instancian para manejo de tablas, relaciones, vistas default, etc. Por lo tanto si vamos a hacer una simple consulta que nos devuelve un registro, el costo de inicialización del dataset supera por mucho el verdadero conjunto de datos del dominio de la aplicación que necesitamos para trabajar.
  2. Si no se usan dataset tipados para trabajar en nuestra aplicación, vamos a tener operaciones de boxing y unboxing cada vez que cargamos el dataset o que modificamos los elementos existentes dentro del mismo. Esto se da porque el Dataset para poder contener cualquier esquema de datos utiliza el tipo object en cada uno de las columnas y por lo tanto cada valor que se obtiene de la fuente de datos se convierte a un object – boxing – y cuando se requiere sacar del dataset se convierte de object al value type requerido – unboxing. Como ya algunos saben, las operaciones de boxing y unboxing son de las más caras que existen en el framework – solo por debajo de algunas como cargar documentos usando el XmlDocument o hacer transformaciones con XSLT.
  3. A la hora de consumir servicios si el servicio expone DataSets la cantidad de XML que se serializa es mucho mayor a la que se genera en el contrato SOAP a la hora de serializar una entidad plana – POCO – y por poco que parezca, cualquier ganancia en lo que respecta a los datos que se envían por el canal es relevante.
  4. Si diseñamos la aplicación y utilizamos UML, todos nuestros esquemas diseñados son inaplicables a este tipo de entidades porque no se puede crear patrones como el adapter o no se puede trabajar directamente sobre el contrato y no la implementación del contrato para tener más libertad a la hora de hacer crecer la aplicación hacia nuevas funcionalidades.
  5. Por la razón anterior, el uso de contenedores de IoC como Unity se vuelve practicamente imposible a nivel de entidades de negocio.
  6. El código desarrollado cuando se trabaja con dataset no tipados es dificil de mantener ya que por lo general las columnas se acceden a través de índices y no a través de nombres en la colección de columnas, por lo que si se agrega o se quita una columna en la base de datos vamos a tener problemas en tiempo de ejecución y no en tiempo de compilación.
  7. Mucha gente utiliza los dataset para escenarios desconectados donde no se tiene acceso al repositorio de datos en un momento determinado, sin embargo estos escenarios son un poco riesgosos ya que si el cliente se queda sin acceso al repositorio por una cantidad de tiempo considerable, puede que su aplicación falle y termine perdiendo todas las operaciones hechas en el dataset durante ese tiempo. Para este tipo de escenarios es mejor tener una base de datos local – SQL server Express y utilizar el Sync Framework de Microsoft para tener los datos sincronizados de manera segura.

Por ahora me quedo con estas razones, aunque tengo algunas más relacionadas a temas de IoC y Transaccionabilidad, pero ocuparía otro post completo para detallarlas. Debo aclarar que la mayoria de las razones expuestas aquí para algunas personas no son relevantes puesto que utilizan diferentes formas de trabajar a las que yo estoy considerando aquí – arquitectura n-layer –; en otros casos no modelan sus aplicaciones en UML y/o tampoco exponen la funcionalidad de su aplicación vía servicios.

Technorati Tags: ,,,

5 comentarios:

Arturo dijo...

Hola Diego. Muy interesante tu post.

Una consulta, ¿como obtengo los datos del servidor de base de datos y lo cargo en colecciones de objetos POCO de la forma más económica posible?

Saludos

Luis D. Rojas dijo...

Hola Arturo,
de muchas maneras, una es usando el EF y convirtiendo las entidades en POCO, otra es utilizando procedimientos almacenados - recomendado - y obteniendo los set de datos con el Data Access Application Block y llenando las entidades via un ciclo ( que al final es lo que hace ADO.NET cuando se llena un dataset )

Admirador dijo...

Interesante artículo.

Comenta: "base de datos local – SQL server Express y utilizar el Sync Framework de Microsoft "

Algún ejemplo real de aplicaciones .net con código fuente que hagan uso de Sync Framework con sql local ?? gracias

Chico dijo...

Saludos Diego, tendrías a mano un ejemplo sencillo de como llenar mediante procedimientos almacenados y el Data Access Application Block los Objetos POCO.

Luis D. Rojas dijo...

Hola chico, gracias por leer el blog. En realidad no tengo un ejemplo ya que además es algo bastante simple. Por ejemplo para carga una lista de algun POCO - llamemolo X - entonces haces una instancia de una coleccion de X, luego traes los datos con un datareader, y por ultimo recorres el reader y llenas la lsita, y luego retornas la lista.
Esto es lo que en resumidas cuentas hace ADO.NET