lunes, 19 de mayo de 2008

ADO Entity Framework , El inicio. (1ra Parte)

Introducción

En el desarrollo de las aplicaciones empresariales es muy frecuente combinar frameworks y plataformas de trabajo con gestores de bases de datos que por lo general constituyen almacenes de datos relacionales. Las capas medias de los grandes y medianos proyectos suelen implementar el paradigma de la programación orientada a objeto. Como es lógico la POO y la programación estructural predominante en los SGBD son incompatibles, a este fenómeno se le conoce como desajuste de impedancia.

El acceso a datos es hace ya más de una década una filosofía que poco ha cambiado, mucha lógica de negocio va a parar a lenguajes basados en SQL, como paquetes o procedimientos de código estructurado dentro de los gestores, provocando entre otras cosas, que un cambio de gestor de datos implique un versionamiento casi total de la aplicación. Pudiéramos pensar que sacando estos segmentos de códigos, transformarlos en SQL estándar y colocarlos como cadenas de consulta dentro de la capa de acceso a datos resolvería este problema y es en gran medida cierto, pero entonces colocamos junto con nuestro código java, c#, c++, etc. , cadenas opacas e intrascendentes a estos lenguajes y sus frameworks. Estas consultas devuelven por lo general datos sin tipos, a los cuales una vez obtenido, hay que realizarle determinadas trasformaciones que nada tiene que ver con el pedido lógico del negocio. A continuación un ejemplo de una clase de acceso a Datos con ADO.NET:

class DataAccess

{

static void GetNewOrders(DateTime date, int qty) {

using (SqlConnection con = new SqlConnection(Settings.Default.NWDB)) {

con.Open();

SqlCommand cmd = con.CreateCommand();

cmd.CommandText = @"

SELECT o.OrderDate, o.OrderID, SUM(d.Quantity) as Total

FROM Orders AS o

LEFT JOIN [Order Details] AS d ON o.OrderID = d.OrderID

WHERE o.OrderDate >= @date

GROUP BY o.OrderID

HAVING Total >= 1000”;

cmd.Parameters.AddWithValue("@date", date);

DbDataReader r = cmd.ExecuteReader();

while (r.Read()) {

Console.WriteLine("{0:d}:\t{1}:\t{2}", r["OrderDate"],

r["OrderID"], r["Total"]);

}

}

}

}

Mapeo Objeto Relacional

Para aliviar este problema de impedancia y ayudar a los desarrolladores a que cada vez más se ocupen del buen diseño de la aplicación de negocio que realicen, han surgido un grupo de frameworks conocidos como ORMs (Object Relational Mappings), mapeo objeto relacional.

Veamos la definición según Miguel Angel Morán [blog] :

“Al proceso de mapeo automatizado entre una entidad del paradigma orientado a objetos a una tabla de una base de datos relacional se le conoce como ORM o lo que es lo mismo Object Relational Mapping”

O sea con este tipo de framework, los desarrolladores pueden crear Entidades inteligentes capaces de persistir en gestores de BD, de forma automática. Este mapeo generalmente hace corresponder a una tabla de la BD una clase en el modelo de entidades. Las relaciones son modeladas de igual manera, incluyendo referencias en cada extremo de las entidades y su multiplicidad la indica el tipo de relación. Por ejemplo A y B se relacionan siendo A el extremo uno o cero y B el extremo mucho, generalmente el mapeo de estas tablas conlleva a que la entidad A tendrán un referencia a una colección de B, y cada entidad B tendrá una referencia a su extremo A. Esto no siempre se cumple como regla, la mayoría de los frameworks dan determinadas flexibilidades a los desarrolladores para ampliar las opciones de mapeo, incluyendo cosas como herencia y mapeo de varias entidades sobre una tabla y viceversa.

En este artículo estaremos viendo ADO.NET Entity Framework, que constituye uno de los pilares del acceso a datos de Microsoft.

ADO.NET Entity Framework

Es un framework desarrollado por Microsoft, aún en versión beta, que forma parte de la familia de ADO.NET para el acceso a datos. Permite, como Framework ORM, modelar los datos desde un nivel conceptual habilitando la separación de la capa de acceso a datos del esquema relacional de la base de datos. De esta forma los datos pueden ser accedidos como objetos de .NET y no como estructuras relacionales y normalizadas. Se alinea con el concepto moderno de implementación de aplicaciones de negocio (LOB) permitiendo al desarrollador acceder a un modelo conceptual. Crea una capa adicional a la aplicación, siendo esta la forma en que se logra la independencia entre los esquemas de BD y los modelos conceptuales. Esta independencia se traduce en la existencia, en la arquitectura del framework, de dos modelos, el de datos y el conceptual (EDM). De esta manera existe un proveedor (provaider) para cada modelo, encargados de realizar el mapeo entre las entidades conceptuales y los datos que mapean y viceversa.

Pero dejemos que los expertos en el tema, abunden más en los principales conceptos que rodean a ADO.NET Entity Framework.

Ver:

http://www.microsoft.com/spanish/msdn/articulos/archivo/041206/voices/

Next-Generation.mspx

http://www.microsoft.com/spanish/msdn/articulos/archivo/041206/voices/

adonetentity.mspx

Instalando componentes

Entrando en un ejemplo práctico del uso de ADO EF, con VS2008 (V9) y el .NET Framework 3.5 en nuestra PC, solo necesitamos instalar tres elementos para comenzar a trabajar.

Links:

http://www.microsoft.com/downloads/details.aspx?

FamilyId=15DB9989-1621-444D-9B18-D1A04A21B519&displaylang=en

http://www.microsoft.com/downloads/details.aspx?
familyid=CF99C752-1391-4BC3-BABC-86BC0B9E8E5A&displaylang=en

http://www.microsoft.com/downloads/details.aspx?

FamilyId=D8AE4404-8E05-41FC-94C8-C73D9E238F82&displaylang=en

Una vez descargados estos instaladores debemos seguir el orden que nos muestra la siguiente figura:

A grandes rasgos:

EFB3SetupX86.exe: Instala el framework ADO EF Beta 3.

VS90-KB945282.exe: Instala unas extensiones para VS 2008, necesario para instalar las herramientas del framework.

EFToolsSetupX86.exe: Instala las herramientas del framework en VS 2008.

Una vez instalados estos 3 elementos solo basta tener acceso a algún Servidor de SQL Server 2000, 2005 donde esté instalado el clásico esquema de BD: Northwind.

Descripción del ejemplo

En este primer ejemplo, trataremos de dar los primeros pasos en el uso del Framework y sus herramientas. Las tablas que mapearemos son:

· Categories

· Products

La relación entre ellas es de 1-* siendo Categories el extremo 1.

Lo que haremos en primera instancia será crear el modelo utilizando las herramientas instaladas en VS.


Pongámonos el overol y a trabajar:

  1. Abrir el VS 2008 y crear un proyecto de consola. Nombrémoslo Mapeo_Productos.
  2. Adicionar elemento al proyecto, click derecho Add->New Item, una vez aquí seleccionar ADO.NET Entity Data Model. Tal como se muestra en la siguiente figura:
3. Presionando el botón Add, comenzamos a configurar un conjunto de elementos en un Wizard que nos provee VS. La siguiente secuencia de imágenes nos indica que poner en cada caso:

Paso1: Seleccionamos generar el modelo desde un esquema de datos.

Paso 2: Seleccionamos la conexión a la BD NortWind y marcamos la casilla tal como muestra la imagen. Con ello garantizamos que la cadena de conexión se escriba en el config de la aplicación.


Paso 3: Seleccionar las tablas que deseamos mapear (Categories y Products) en este modelo así como nombrar el Namespace donde se generarán las clases .NET que mapean dichas tablas.

Paso 4: Pulsamos el botón Finish y listo, tenemos creado nuestro primer modelo.


4. El modelo generado se observa tal como la siguiente imagen:

En la parte inferior observe como cada atributo de la tabla Categories es mapeados por una propiedad de la clase Categories generada en el modelo.

1.55. Finalmente nuestro Solution Explorer debiera verse de la siguiente forma:

Están marcados los Assamblys que se incluyen automáticamente como referencias así como el modelo generado.

Llegados a este punto describamos un poco el código generado por las herramientas.

[assembly: global::System.Data.Objects.DataClasses.
EdmSchemaAttribute()]

[assembly: global::System.Data.Objects.DataClasses.
EdmRelationshipAttribute(

"NorthwindModel","FK_Products_Categories", "Categories", global::System.Data.Metadata.Edm.RelationshipMultiplicity.
ZeroOrOne,
typeof(NorthwindModel.Categories), "Products",
global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many,
typeof(NorthwindModel.Products))]

// Original file name:

// Generation date: 18/05/2008 20:37:17

namespace NorthwindModel

{

///

/// There are no comments for NorthwindEntities in the schema.

///

public partial class NorthwindEntities:
global::System.Data.Objects.ObjectContext

{

///

/// Initializes a new NorthwindEntities object using the connection
string found in the 'NorthwindEntities' section of the application
configuration file.

///

public NorthwindEntities() :

base("name=NorthwindEntities", "NorthwindEntities")

{

}



}

Observamos en la cabecera de este código el atributo [...EdmSchemaAttribute] que indica que la próxima línea constituye un atributo del modelo generado. Esta línea siguiente es la definición de la relación de navegación entre la clase [Categories] y la clase [Products], indicando de qué tipo es (ZeroOrOne) y que propiedad la encierra en cada extremo. Describe para el framework quien es el extremo uno y quien es el extremo muchos.

Un poco más abajo, dentro del namespace NorthwindModel, se generó la clase NorthwindEntities, que hereda de la clase ObjectContext. Esta es la clase encargada de mantener la conexión e información de los metadatos necesaria para leer, escribir, actualizar o borrar entidades en la BD. O sea constituye la llave o entrada, entre el modelo conceptual y la BD. Además referencia internamente a la clase ObjectStateManager, encargada del seguimiento de las entidades en cuanto a cambios y resolución de identidades, de ella estaremos comentando en próximas publicaciones.

[global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(Namespace
Name="NorthwindModel", Name="Categories")]

[global::System.Runtime.Serialization.DataContractAttribute()]

[global::System.Serializable()]

public partial class Categories : global::System.Data.Objects.DataClasses.EntityObject

{

///

/// Create a new Categories object.

///

///
Initial value of CategoryID.

///
Initial value of CategoryName.

public static Categories CreateCategories(int categoryID, string categoryName)

{

Categories categories = new Categories();

categories.CategoryID = categoryID;

categories.CategoryName = categoryName;

return categories;

}

///

/// There are no comments for Property CategoryID in the schema.

///

[global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute

(EntityKeyProperty=true, IsNullable=false)]

[global::System.Runtime.Serialization.DataMemberAttribute()]

public int CategoryID

{

get

{

return this._CategoryID;

}

set

{

this.OnCategoryIDChanging(value);

this.ReportPropertyChanging("CategoryID");

this._CategoryID = global::System.Data.Objects.DataClasses.
StructuralObject.SetValidValue(value);

this.ReportPropertyChanged("CategoryID");

this.OnCategoryIDChanged();

}

}



}

En esto otro segmento de código generado se muestra la clase Categories, marcada como tipo de entidad del modelo (EdmEntityTypeAttribute), como clase Serializable y como DataContractAttribute, este último tiene que ver mucho con la relación que existe de forma natural entre las entidades generadas y el modelo de programación WCF, pero esto es un tema que estaremos viendo a fondo muy pronto por aquí. Se muestra además la propiedad CategoryID, que mapea la llave primaria de la tabla Categories, nótese que entre un conjunto de operaciones que se realizan en el set de la property , se realiza una llamada el método SetValidValue,quien se encarga de asignar un ID (Auto-Numérico) válido a la entidad.

Llegados a este punto, pongamos al framework en acción. Lo que trataremos de realizar ahora será una consulta a los datos existentes en la tabla. Antes que nada dejemos a un lado las viejas prácticas de acceso a datos y preparémonos para algo realmente sorprendente: Linq to Entities.

Para consultar los datos del modelo existen tres posibles formas:

  • EntityClient
  • Servicios del objeto
  • Linq to Entities.


En este artículo veremos dos de ellas. Comenzamos por encuestar al modelo mediante servicios de Objeto, el código para obtener el nombre de los productos cuya categoría es: “
Beverages” es el siguiente:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data.EntityClient;

using System.Data.Common;

using System.Data;

using NorthwindModel;

using System.Data.Objects;

namespace Mapeo_Productos

{

class Program

{

static void Main(string[] args)

{

string Category = "Beverages";

NorthwindEntities model = new NorthwindEntities();

ObjectQuery query = model.CreateQuery(

"SELECT VALUE p FROM Products AS p INNER JOIN Categories AS c on p.Categories.CategoryID = c.CategoryID where c.CategoryName = @Category",

new ObjectParameter("Category", Category));

foreach (Products c in query)

Console.WriteLine(c.ProductName );

Console.ReadKey();

}

}

}


Note que la consulta está basada en SQL y para poder ejecutarla no en necesario crear conexiones ni otro tipo de configuración inicial, solo crear el objeto de contexto
NorthwindEntities, crear un ObjectQuery<Products>, al cual debemos pasar la cadena SQL, pero teniendo en cuenta que estamos consultando nuestro modelo y no la base de datos, de ahí que la condición de INNER JOIN sea: p.Categories.CategoryID = c.CategoryID y no: p.CategoryID = c.CategoryID, como normalmente se realiza sobre la BD. Accedemos a las categorías de un producto mediante la property Categories de la entidad Products. El resultado debiera ser algo parecido a lo que muestra la siguiente imagen.

Hasta este momento podemos no notar grandes ventajas para los desarrolladores, pero observemos el siguiente código que devuelve los mismos resultados que el anterior:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data.EntityClient;

using System.Data.Common;

using System.Data;

using NorthwindModel;

using System.Data.Objects;

namespace Mapeo_Productos
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities model = new NorthwindEntities();

List<Products > query = (from p in model.Products

where p.Categories.CategoryName == "Beverages"

select p).ToList();

foreach(Products c in query)

Console.WriteLine(c.ProductName);

Console.ReadKey();
}
}
}

Esta maravilla se conoce como Linq To Entities, ese poderoso lenguaje de consulta incluido en el .NET framework 3.5, cuenta con soporte para ADO EF lo cual hace las delicias de muchos desarrolladores. Pero bueno dejemos el comercial detrás y expliquemos un poco el código. Como en los Servicios de Objeto, lo primero es crear una instancia de nuestro Modelo, para luego encuestarlo haciendo uso de Linq, en este caso, tomando model.Products como Source y navegando desde los productos hacia las categorías, gracias a la property Categories, obtenemos todos los productos de nuestra BD que cumplen la condición expuesta. Este resultado lo casteamos a una lista de productos (List<Products>) para mostrar en pantalla los resultados. Esto pudiera parecer incómodo pues tiene mucha similitud con SQl, probemos entonces algo como esto:

class Program

{

static void Main(string[] args)

{

NorthwindEntities model = new NorthwindEntities();

List<
Products > query = model.Products.Where(p => p.Categories.CategoryName == "Beverages").ToList();

foreach(Products c in query)

Console.WriteLine(c.ProductName);

Console.ReadKey();

}

}

}

De igual forma obtenemos los mismos resultados.

Hasta aquí este primer acercamiento a ADO EF. Espero que le haya sido productivo y cuando tenga que crear capas de acceso a datos para sus proyectos, piense en ADO EF como una opción real que potenciará su productividad. En próximos artículos estaré comentando acerca de cómo realizar las operaciones CRUD sobre las entidades de este modelo. Nos vamos, nos vemos.

viernes, 2 de mayo de 2008

Conociendo SOA - I Parte

Este artículo constituye el primero de una serie, dirigida a la comprensión de los conceptos que rodean los enfoques modernos de las TI. Describe fundamentalmente los principios de la orientación a servicios como paradigma que ha evolucionado en la actualidad.

No pretende ser un manual o tutorial de cómo afrontar un proyecto SOA, sino que viene a cubrir aspectos importantes que a menudo se mencionan pero que no se conocen a fondo.

Para su confección, ha sido consultado un conjunto amplio de documentación moderna, destacando los aportes de Thomas Erl, a través de sus libros: SOA, Principios de Diseño y SOA, Conceptos, Tecnología y Diseño, considerados estas publicaciones enciclopedias del tema.

1. Algunas definiciones importantes.

Principio de Diseño: Generalmente es una práctica aceptada por la industria que se promueve como especie de guía para lograr objetivos de manera eficiente. Estos objetivos a cumplir o principios son asociados con las características de diseño que deben tener las soluciones que se basen en estos principios.

Paradigma de Diseño: Representa un conjunto de principios de diseño o reglas que pretende marcar un patrón o modelo. Representan los antecedentes funcionales a una solución de diseño.

Patrón de Diseño: Un patrón de diseño es una solución a un problema de diseño. Para que una solución sea considerada un patrón debe poseer ciertas características. Una de ellas es que debe haber comprobado su efectividad resolviendo problemas similares en ocasiones anteriores. Otra es que debe ser reusable, lo que significa que es aplicable a diferentes problemas de diseño en distintas circunstancias.

2. Origen e Influencia en la orientación a Servicios.

La mejor forma de entender algo, muchas veces es la de partir de su surgimiento y su historia. La orientación a servicios es un paradigma de diseño que no representa una revolución, sino una evolución de las tecnologías de la información que tiene raíces en paradigmas pasados y en la propia evolución de las tecnologías. El siguiente gráfico muestra algunos de los elementos que mayor influencia han ejercido hacia la evolución de la orientación a servicios.


Fig 1. Orígenes e influencia en la Orientación a Servicios.

Orientación a Objetos

En la década de los ’90, la comunidad de desarrolladores de sistemas asumió como filosofía de diseño para afrontar los diversos tipos de soluciones. Este paradigma incorpora una serie de principios que definen un tipo específico de relación entre las unidades lógicas de la solución, conocidos como objetos.

La orientación a servicios es comparada frecuentemente con la orientación a objetos, pues los principios y patrones de diseño de este último, representan una de las fuentes de inspiración más importantes para la evolución de este paradigma.

Principios como la reutilización Reusabilidad, Abstracción, Encapsulación, entre otros tienen sus homólogos en el paradigma Orientado a Servicios.

Web Services

A pesar de que la orientación a servicios es un paradigma y SOA una arquitectura tecnológica cuya implementación es neutral, el asociarlos (SOA+Orientación a Servicio) con los web services es muy común. Fundamentalmente dado por la promoción que realizan los principales proveedores de herramientas SOA cuyas plataformas están basadas en el framework Web Services.

Los framework de Web Services promueven un conjunto de principios de la orientación a servicios: Abstracción, Bajo Acoplamiento y composición de servicios.

BPM

Se llama Business Process Management a la metodología empresarial cuyo objetivo es mejorar la eficiencia a través de la gestión sistemática de los procesos de negocio (BPR), que se deben modelar, automatizar, integrar, monitorizar y optimizar de forma continua.

Como su nombre sugiere, Business Process Management (BPM) se enfoca en la administración de los procesos del negocio. Esta capa es la parte fundamental de cualquier arquitectura SOA desde la perspectiva de la composición de servicios que generen el flujo de un proceso de negocio. Los sistemas BPM generalmente asumen el rol de controladores de la composición de servicios.

Uno de los principales objetivos de la orientación a servicio es establecer un entorno ágil de automatización capaz de adaptarse rápidamente a los cambios del entorno de negocio. Esto es posible realizando servicios que encapsulen la lógica de negocio mayormente reutilizable y componer los procesos de negocio partiendo de la orquestación de estos servicios.

Integración de Aplicaciones Empresariales

Las empresas desde las década de los ’90 han protagonizado una explosión de aplicaciones hacia el interior, orientadas a resolver problemas específicos y pocas veces pensadas para interoperar unas con otros. Los enfoques sistémicos de las organizaciones promueven cada vez más la integración de las aplicaciones monolíticas mencionadas.

Las plataformas EAI introducen middlewares que abstraen la integración entre las aplicaciones mediante la creación de conectores, adaptadores y servicios que hacen interoperables sistemas diferentes.

Varios proyectos de integración se basan en SOA, específicamente en el uso de web services y la orquestación de servicios que combinan datos de varias aplicaciones.

3. Principios de Orientación a Servicios.

Existen muchas definiciones de SOA, pero en general la mayoría de los proveedores de TI, coinciden en que la orientación a servicios se rige por 8 principios fundamentales. La orientación a servicio constituye una teoría que guía la ingeniería de software hacia soluciones SOA. Estos principios son generalmente implementados por las plataformas y herramientas utilizadas para las soluciones. Existe una analogía entre los principios de la orientación a objetos, y las plataformas de desarrollo (.net, java) de forma similar a como se vinculan la orientación a servicios con las plataformas y estándares de la industria (web services).

Los principios de la orientación a servicios son:

1. Los Servicios son reusables.

2. Los Servicios proporcionan un contrato formal.

3. Los Servicios tienen bajo acoplamiento.

4. Los Servicios permiten la composición.

5. Los Servicios son autónomos.

6. Los Servicios no tienen estado.

7. Los Servicios encapsulan la lógica.

8. Los Servicios pueden ser descubiertos.

Para que una solución sea 100% SOA, debe cumplir con cada uno de estos principios. Muchos expertos recomiendan asumir los proyectos de forma escalonada dando cumplimiento a los principios poco a poco.

Hasta aquí esta primera parte, mas adelante serán abordados estos principios y su aplicación real en aplicaciones empresariales. En la medida de lo posible, cada principio irá acompañado de ejemplos prácticos sobre el modelo WCF de .NET Framework 3.0.


Rompiendo el hielo

Bienvenidos a mi blog, espero compartir aquí con todos aquellos colegas que asi lo deseen, temas vinculados a la informática, específicamente al desarrollo de aplicaciones empresariales. Soy graduado de Ingeniería Informática en la Cujae.

Espero poder debatir sobre varios temas, la mayoría vinculados a la tecnología .NET, arquitectura SOA y BPM. En estos momentos soy desarrollador de la Empresa DATYS, trabajando en sistemas de soporte a la toma de decisiones, así que por estos rumbos estarán las entradas que se irán publicando. Espero que mis amigos me regalen un poco de su tiempo y podamos crear interesantes debates, y como no, conocer a aquellos amigos futuros.

De antemano muchas gracias por compartir conmigo su preciado tiempo.