Tuesday, March 18, 2008

ADO.NET Entity Framework en una Aplicación Distribuida y Conceptos de Arquitectura Útiles.












Hey! cómo han estado? wow...es bueen tiempo ya el que he estado alejado de este blog debido a las diversas actividades que he estado realizando en mi trabajo y como Microsoft Speaker, sin embargo he venido a traer algo que me ha parecido interesante hacer, y es que con la salida del .NET Framework 3.5 y Visual Studio 2008 pues han aparecido varias características interesantes en lo que respecta a acceso a datos, entre ellas:










Linq To Entities
Linq To Objects





Linq To SQL











y una muy interesante (o que al menos a mi me lo pareció): ADO.NET Entity Framework.











ADO.NET Entity Framework, no es en sí una característica del lenguaje (como sí lo es Linq por ejemplo), sino más bien una infraestructura construída sobre el .NET Framework 3.5 (aprovechando Linq de paso), que permite crear un modelo de objetos en base a una base de datos relacional. ¿Qué es ésto? Pues muchos hemos trabajado con generadores de código y modelos relacionales que nos conectaban a bases de datos, pero el problema siempre era esa impedancia entre lo que es un modelo plano de tablas a un modelo de objetos. Por ejemplo en un modelo de tablas y columnas (por ejemplo de la base de datos Northwind), tendríamos en la tabla Product una referencia a su categoría a través de la columna CategoryID, de modo que si usáramos un modelo 1 a 1 (de los cuáles hay varios), tendríamos exactamente lo mismo replicado en clases .NET:











/////////////////////////////////////////





Product product = ProductLogic.GetProductById(3);





int categoryID = product.CategoryID;





Category category = CategoryLogic.GetCategoryById(categoryID);





Console.Write(category.CategoryName);










//ProductLogic y CategoryLogic son objetos que nos traerán información





//de algún repositorio, por el momento es indistinta su naturaleza.





///////////////////////////////////////////











Como vemos este modelo funciona, pero no es muy orientado a objetos que digamos, pues lo que esperaríamos sería algo como:












/////////////////////////////////////////

Product product = new ProductLogic.GetProductById(3);
Console.Write(product.Category.CategoryName);

///////////////////////////////////////////













Pues bien, cierto es que se puede manipular el código generado por diversas herramientas (como la ahora "ya no soportada por Microsoft" Repository Factory ), pero ésto se convertía a veces en algo tedioso. Cierto es también que esquemas como el de Linq to SQL, también crea un modelo de objetos bastante pulcro y entendible, pero lo interesante del ADO.NET Entity Framework (a la fecha 18 de Marzo del 2008 en Beta 3), es que supone la creación de una capa más, que va más allá de mapear una base de datos, sino de verdaderamente inferir las relaciones entre objetos y crear un modelo bastante más complejo de aquellos a los que las habituales herramientas de generación de código nos tienen habituados. Por ejemplo, una entidad puede estar representada en una base de datos en 2 tablas, pero en el modelo de objetos en una sola clase. Cosas como esa son ahora un "poco más" posibles con ADO.NET Entity Framework.












Aquí, gracias a Jorge Serrano, puedes ver un buen ejemplo de cómo utilizar ADO.NET Entity framework, te recomiendo que lo leas ANTES de seguir.












Bien, ¿ya lo leíste? Pues ahora, vamos a empezar con algunos ejemplos.












Para comenzar haremos una aplicación como la que desarrolló Jorge Serrano en el ejemplo que te indiqué antes:













Para ésto utilizaré:












ADO.NET Entity Framework Beta 3 (EF)











Microsoft Visual Studio 2008 RTM











Microsoft SQL Server Express Edition











Base de Datos Northwind













1. Creamos primero un proyecto de Aplicación de Windows en Visual Studio 2008, y le agregamos un nuevo elemento, seleccionamos ADO.NET Entity Data Model, yo le he puesto al modelo "Northwind":


















































Una vez que tengamos el modelo agregado, aparecerá un asistente para configurar el modelo (imagino que estos pasos ya los deben haber visto en el ejemplo de Jorge, así que los omitiré). Finalmente tenemos un modelo de objetos que se verá algo así (yo he elegido todas las tablas y he puesto por Entity Container Name al modelo el nombre NorthwindEntities):


































Pues bien, hasta ahora nada nuevo (si es que han leído el ejemplo de Jorge!)






















Pues bien, veremos que si agregamos el siguiente código y objetos al formulario podremos ver las categorías almacenadas en la tabla Categories de la base de datos Northwind.























NorthwindEntities db = new NorthwindEntities(); //Instancio el contexto del modelo











dgvCategories.DataSource = db.Categories; //Invoco a la entidad Categories













Pues bien, ahora empieza lo bueno. En el ejemplo de Jorge Serrano deben haber visto ya que es posible separar la capa de Acceso a Datos (donde está el modelo del EF) y la de interfaz de usuario (el .EXE :) ). Pues vamos a hacer algo más.








Como saben, las aplicaciones distribuidas del día de hoy exigen el cumplimiento de ciertos estándares de desarrollo, cierto es que los patrones no siempre son aplicables a todo, ni tampoco tenemos por qué mater un mosquito con mi misíl, pero quisiera dejar en esta serie una idea de cómo distribuir nuestra aplicación que usa a nivel de acceso a datos al EF. Lo haré haciendo que la interfaz de usuario consuma un servicio WCF (Windows Communication Foundation), que por detrás se comunique, usando un esquema de arquitectura bien definido, con el EF para obtener los datos requeridos.








El esquema de arquitectura que voy a implementar es el mismo que implementan Guidance Packages como el de la Service Factory: Modeling Edition (antes Web Service Factory). Es una larga historia por ahí (les recomiendo que se descarguen la factory y la prueben, está muy buena, es extendible y además cambia el paradigma a "empezar por el diseño" 8-) ). Al fin el esquema que tendremos será el siguiente (al lado he puesto los espacios de nombre que usaré):












  • Interfaz de Usuario (TestLinq)




  • Interfaz Servicio WCF (Northwind.Services)




  • Implementación de Servicio WCF (Northwind.ServiceImplementation)




  • DataContracts de WCF (Northwind.DataContracts)




  • Lógica de Negocio (Northwind.BusinessLogic)




  • Entidades de Negocio (Northwind **)




  • Acceso a Datos (Northwind **)




  • Base de Datos (Base de Datos Northwind en Motor de SQLEXPRESS)








** A este nivel es interesante notar que en un modelo común (en el que se implementan por un lado las Entidades de Negocio y por otro las clases de acceso a datos, se tendrían dos espacios de nombres, por ejemplo: Northwind.BusinessEntities y Northwind.DataAccess respectivamente. Sin embargo, el esquena del EF integra en uno el acceso a datos y entidades que, en este caso, consumiré yo como entidades de negocio).




Sería bueno también que revisen un poco de documentación sobre los DataContracts, pues yo seré breve y sólo diré que es una manera de representar tipos complejos que deban ser intercambiados a través de los mensajes intercambiados en un servicio (en este caso WCF). Dichos DataContracts deben ser serializables para WCF (con el atributo [DataContract]), y sus propiedades con el atributo [DataMember]). Por ejemplo, si queremos un método que nos devuelta una lista de categorías tendremos algo como (en el servicio):








public void List<Category> GetAllCategories () { .... }








donde Category es un DataContract.








[DataContract]




public class Category{ ... }
























Explicando la Arquitectura












A continuación les voy a explicar cómo es que funciona la arquitectura planteada aquí. La idea es que un servicio WCF intercambie con una interfaz de usuario DataContracts. Cuando uno invoca a un servicio WCF desde una aplicación (Windows/Web), a través de un proxy generado (con la herramienta svcutil.exe), el servicio debe en realidad hacer una llamada a una acción de lógica de negocio (Northwind.BusinessLogic). Esta acción será la encargada de (de ser necesario), conectarse a una base de datos (Northwind) a través de las clases de acceso a datos (para nuestro caso el modelo de EF "Northwind.edmx"). Cabe destacar que las clases de la capa BusinessLogic (generalmente nombradas con el sufijo Action) intercambian con la capa de Acceso a Datos instancias de Entidades de Negocio, que son clases que forman el modelo de dominio de nuestra aplicación (en nuestro caso representado también por el modelo de EF Northwind.edmx). Estas Entidades de Negocio NADA TIENEN QUE VER (por especificación de la buena práctica de diseño) con ningún tipo de implementación WCF, ésto es, no tienen por qué amarrarse a una tecnología específica de distribución, pues eso iría en contra de la idea de DESACOPLAMIENTO que estamos buscando. Dichas clases (Entidades de Negocio) deben luego ser TRADUCIDAS a DataContracts para que su información pueda ser expuesta a través de un servicio WCF.






Cierto es que podría lanzarse la pregunta "pero si las ENTIDADES DE NEGOCIO nada tienen que ver con tecnologías, ¿por qué están entoncesa AMARRADAS al Entity Framework?", pues en este caso, por definición de la tecnología de EF y aprovechamiento de sus ventajas, es así, pero ojo EF NO ES LA SOLUCIÓN A TODOS LOS CASOS, va a haber situaciones en las que sí debas programar tú mismo tus entidades de negocio y tus clases de acceso a datos (las famosas DAL) POR TI MISMO :)






Vamos a por ello:






Creamos un proyecto de tipo Class Library llamado Northwind.DataAccess, al cual le agregamos un modelo de EF llamado Northwind.edmx y le agregamos las tablas de la base de datos Northwind. Luego compilamos y procedemos a incluir los archivos creados: Northwind.csdl, Northwind.msl y Northwind.ssdl, en el proyecto y luego los configuramos como Embedded Resources a fin de que se incluyan en el ensamblado generado y no tengamos que estar copiando y pegando dichos archivos para distribuir la aplicación(en el ejemplo de Jorge aquí se muestra cómo hacer eso y se explica más a detalle el por qué es bueno hacer ésto). El ObjectContext del modelo se llama NorthwindEntities y el nombre lo puedes establecer mediante la propiedad del modelo Entity Container Name. El Namespace del modelo es Northwind y lo puedes establecer a través de la propiedad del modelo Namespace (clic derecho en la superficie del modelo)












Creamos un proyecto de tipo Class Library llamado Northwind.BusinessLogic, al cual agregaremos un referencia al proyecto Northwin.DataAccess. Luego creamos la clase GetAllCategoriesAction y escribimos un método llamado Execute. Las clases de la Capa de Lógica de Negocio llevan por lo general (según lo que he leído varias veces) el sufijo Action y un único método Execute. La idea es que se tenga un repositorio de muuuuchas Actions que luego sean orquestadas por un Servicio WCF ORQUESTADOR (que puede orquestara su vez a otros servicios WCF...ajá!..si ya estás pensando en TransactionScope en estos servicios orquestadores vas bien).







namespace Northwind.BusinessLogic
{
///
/// Represents a Business Action for Getting all the Categories.
///

public class GetAllCategoriesAction
{
public List<Categories> Execute()
{
NorthwindEntities db = new NorthwindEntities();
List<Categories> categoryList = db.Categories.ToList();
return categoryList;
}
}
}

Lo que el método hace es simplemente instanciar el ObjectContext NorthwindEntities y devolver la propiedad Categories, que nos devolverá una instancia de ObjectQuery<Categories>. En mi caso para simplificar el modelo convierto el ObjectQuery<Categories> en un List<Categories> con el método ToList(). Categories es el nombre de la entidad generada en el modelo Northwind.edmx a partir de la base de datos Northwind. Hasta este punto no hemos tocado la tecnología WCF y sin embargo ya contamos con una acción de negocio (regla de negocio si quieres llamarle así), y es así como debería ser, vamos bien.
Ahora vamos a crear la implementación del servicio WCF. Recordemos que un servicio WCF no es exactamente un servicio Web, sino una clase o interfaz como cualquier otra pero marcada con el atrituto [ServiceContract] y cuyos métodos a "exponer" están marcados con el atributo [OperationContract]. Otra cosa es que generalmente se vea en los ejemplos que está HOSTEADA en una aplicación web (un servidor IIS).
Agregamos a la solución el proyecto Northwind.ServiceImplementation. A éste le agregamos la interfaz INorthwindService y la clase que implementa dicha interfaz NorthwindService. También agregamos las referencias a System.Runtime.Serialization, System.ServiceModel.


[ServiceContract]
public interface INorthwindService
{
[OperationContract]
ListCategory> GetAllCategories();
}


public class NorthwindService : INorthwindService
{
public ListCategory> GetAllCategories()
{
return null;
}
}
Si te das cuenta la clase Category no aparecerá de verde en tu código fuente. Y es porque aún no existen los DataContracts que tu servicio debe devolver.
Creemos entonces los DataContracts. Agregamos a la solución el proyecto Northwind.DataContracts, y la clase Category que será el DataContract que será usada en nuestro servicio WCF:

namespace Northwind.DataContracts
{
///
/// DataContract for Category
///

[DataContract]
public class Category
{
[DataMember]
public int CategoryId { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public byte[] Picture { get; set; }
}
}


Chispas!..hora de partir!..prometo seguir escribiendo!!!...jeje :D
muchas bendiciones!:D













































Labels:

Thursday, February 22, 2007

Qué hay con el sp_ExecuteSQL?

Cómo están? después de muuucho tiempo que me animo a escribir algo por aquí (si acaso no ven algo nuevo revisen mis otros blogs o en el Guille). Me había puesto a revisar viejo código que tenía por ahí y encontré algo que hice para un sistema allá por el 2002, que si bien puede parecer "anticucho" (jojo), puede que le sirva a alguien por ahí.
Se trata del uso del procedimiento almacenado sp_executeSQL. Éste es un procedimiento almacenado del sistema que, como dice su nombre, se encarga de ejecutar bloques de T-SQL. Y dónde está lo bonito? en que esos bloques los pasamos como cadenas, de modo que puedes "construir" tu consulta "a gusto propio" y "al vuelo" y finalmente ejecutarla.
Digamos que (desde el punto de vista de un usuario), se quieren ver ciertos datos filtrados en la aplicación cliente:
1. Bien, traemos un DataSet, DataTable o algo parecido y lo filtramos en el cliente
2. Creamos un procedimiento almacenado en el servidor que reciba una cierta cantidad de parámetros conforme al filtro que hacemos
Ahora bien, digamos que (por alguna razón, talvez algo que sólo se use una vez al día), no necesitamos traer todo el conjunto de datos al cliente, sino sólo ( y talvez a modo de cursos como en un DataReader), los datos ya filtrados. Si ese es el caso podríamos usar la opción 2, pero habría un problema, y sería que en realidad UNO NO SABE SINO HASTA EL MOMENTO EN QUE EL USUARIO HACE LA CONSULTA, LA CANTIDAD DE PARÁMETROS QUE SERÁN REVELANTES EN LA CONSULTA. Ahora bien, uno podría armar una consulta en T-SQL en el cliente, o en alguna clase de lógica de negocio (lo que sería bueno); pero si por alguna razón no se cuenta con ello (o se quiere implementar directamente sobre la BD), pues es cuando podemos hacer uso del sp_executeSQL, pidiendo parámetros fijos en la llamada al procedimiento almacenado y luego simplemente armando la consulta conforme se hayan dado ciertos valores a los parámetros.
Pongo aquí un ejemplo de un Procedimiento Almacenado que hice por esos tiempos:

La idea es que tenemos una serie de tablas asociadas de donde queremos extraer sólo ciertos registros en base a los parámetros que proporcionemos. De este modo, como los parámetros son estáticos, pues la llamada siempre será igual, pero dependiendo de sus valores, la consulta se reorganizará.

CREATE PROCEDURE [dbo].[GetHistoricoFiltros]
@CriterioFechas Bit = 0,
@FechaInicio Char(8) = '19000101',
@FechaFin Char(8) = '19000101',
@CriterioConcepto Bit = 0,
@Concepto1 Char(3) = '',
@Concepto2 Char(3) = '',
@Concepto3 Char(3) = '',
@CriterioRecibo Bit = 0,
@Recibo Char(10) = '',
@CriterioMoneda Bit = 0,
@Moneda Char(1) = '',
@CriterioMovimiento Bit = 0,
@Movimiento Char(1) = '',
@CriterioCliente Bit = 0,
@Cliente Char(5) = ''
AS
Declare @BasicSQL nChar(3000)
Declare @FiltroFechas Char(200)
Declare @FiltroConceptos Char(100)
Declare @FiltroRecibo Char(100)
Declare @FiltroMoneda Char(100)
Declare @FiltroMovimiento Char(100)
Declare @FiltroCliente Char(100)
Declare @NextConnector Char(10)
Set @FiltroFechas = ''
Set @FiltroConceptos = ''
Set @FiltroRecibo = ''
Set @FiltroMoneda = ''
Set @FiltroMovimiento = ''
Set @FiltroCliente = ''
Set @NextConnector = ' Where '
IF @CriterioFechas = 1
Begin
Set @FiltroFechas = @NextConnector + " dbo.HistoricoCajaChica.FechaRegistro > '" + @FechaInicio + "' And HistoricoCajaChica.FechaRegistro < '" + @FechaFin + "'"
Set @NextConnector = ' And '
End
If @CriterioConcepto = 1
Begin
Set @FiltroConceptos = @NextConnector + " HistoricoCajachica.CodGasto IN ('" + @Concepto1 + "','" + @Concepto2 + "','" + @Concepto3 + "')"
Set @NextConnector = ' And '
End
If @CriterioRecibo = 1
Begin
Set @FiltroRecibo = @NextConnector + " HistoricoCajaChica.NumRecibo = '" + @Recibo + "'"
Set @NextConnector = ' And '
End
If @CriterioMoneda = 1
Begin
Set @FiltroMoneda = @NextConnector + " HistoricoCajaChica.Moneda = '" + @Moneda + "'"
Set @NextConnector = ' And '
End
IF @CriterioMovimiento = 1
Begin
Set @FiltroMovimiento = @NextConnector + " HistoricoCajaChica.Movimiento = '" + @Movimiento + "'"
Set @NextConnector = ' And '
End
If @CriterioCliente = 1
Begin
Set @FiltroCliente = @NextConnector + " HistoricoCajaChica.Cliente ='" + @Cliente + "'"
Set @NextConnector = ' And '
End
Set @BasicSQL = 'SELECT dbo.HistoricoCajaChica.NumRecibo AS [Recibo/Factura], dbo.HistoricoCajaChica.Movimiento AS [Mov ], CONVERT(Char(10),
dbo.HistoricoCajaChica.FechaRegistro, 103) AS [Fecha Ingreso], CONVERT(Char(10), dbo.HistoricoCajaChica.FechaCerrado, 103) AS [Fecha Cierre],
dbo.Empresa.RazonSocial AS [Agencia/Hotel], dbo.HistoricoCajaChica.Pagador AS Nombre, dbo.GastoCaja.Concepto AS Concepto,
dbo.HistoricoCajaChica.Moneda, dbo.HistoricoCajaChica.Monto_MN AS Soles, dbo.HistoricoCajaChica.Monto_ME AS Dólares,
dbo.HistoricoCajaChica.Observaciones, dbo.Usuario.NombreLargo AS [Ingresado Por], dbo.HistoricoCajaChica.Identificador AS Idt
FROM dbo.HistoricoCajaChica INNER JOIN
dbo.GastoCaja ON dbo.GastoCaja.CodGasto = dbo.HistoricoCajaChica.CodGasto INNER JOIN
dbo.Usuario ON dbo.Usuario.CodUsuario = dbo.HistoricoCajaChica.CodUsuario INNER JOIN
dbo.Empresa ON dbo.Empresa.CodEmpresa = dbo.HistoricoCajaChica.Cliente'

Set @BasicSQL = RTrim(@BasicSQL) + RTrim(@FiltroFechas) + RTrim(@FiltroConceptos) + RTrim(@FiltroRecibo) + RTrim(@FiltroMoneda) + RTrim(@FiltroMovimiento) + RTrim(@FiltroCliente) + ' ORDER BY dbo.HistoricoCajaChica.NumRecibo, Soles'
exec sp_executesql @BasicSQL

Bueno, ojalá a alguien le sirva o le de una idea....a veces...lo viejo sirve..también..



también publiqué este post en mi otro blog: community.palazzetti.net/blogs/javi_davi

Labels:

Saturday, September 02, 2006

Just in case you didn't know.....I am a Microsoft Student Partner (formerly Microsoft Student Ambassador),...if you wanna find out more about that check out http://salatam.net , bye-bye!

xAml???

Even if many of you may think that talking about what xAml is might seem late on these days, I'll do it, because there are many people who don't know about it yet.

So, what is this xAml all about?

xAml stands for eXtensible Application Markup Language, it is a declarative language derived from XML (which stands for eXtensible Markup Language). It is used to define rich user interfaces with simple declaration of sections and parameters. So, that's why I capitalize the "A" in xAml, since its main purpose is to define UIs.

xAml is closely related to Windows Presentation Foundation (WPF), which is one of the bases of the "new" Microsoft .NET Framework 3.0 (I'll talk about this later but you can find out more at here. The vision of WPF is to bring a new way to build rich smart clients with media support (video, audio, pictures), 2D and 3D capabilities, incorporating UIs and documents.

Thanks to xAml we finally are able to finish the looooong term discussions between designers and developers. Do you remember how cool it was when ASP.NET came up with its "code-behind" (then) schema? At last we could forget about the "spaghetti" code (mixing HTML tags and source code in one file), not only because it was hard to maintain, but because it was hard to make the page designer work with the developer, they all together, so they could become more productive. Plus, it usually happened that the page designer "changed" something in the page and some portion of source code didn't work properly, or viceversa...this because the designer didn't know about source code (he or she maybe deleted something)..or the developer added a few more columns to a table, making all the graphics on the page aside ...(and look horrible!!!)...Well, now that's possible not only in web development, but in Windows Forms applications development. Uhmmm....actually, with WPF this division between Web and Windows Forms development is not "that" big, since everything will be the same now: just xAml, so for switching from a "Windows" application to a "Web" application, you will only need to change a parameter (ok, maybe a few more), but that's it! Voila! Two years programming your cool application and your boss told you "now we want it a web app"???? don't be afraid, just run it on a web browser, that's the idea! Anyways,..what was I talking about??? uhmmm...ok!..now the windows designer and the windows programmer will start from the same prototype (defined in a Use Case Specification, maybe) but will be able to work side-by-side, with different files and to maximize their capabilites.....

...all that, thanks to xAml.

I know maybe this is not a very complete document about xAml but I tried to let you know how it will finally help you when developing, ....hope you keep on finding out about xAml and God bless :).......






Saturday, August 26, 2006

Home-oriented software development?

Many times we listen about what's new on corporative software development, and how all those Web Services, Components, and little programs nobody really understands make business bigger...FROM INSIDE, making the flow of information from area to area bigger and eficient. However, what about our houses?, I know there's a lot of products (today) that make our lives "happier"-like TVs, DVD-Players, etc,......- but, what about make our life "EASIER"?

I know about a couple of companies (actually many of them), that are developing ("in secret") systems for that purpose: "making our lives easier". Ok, that's ok, so....once they've done it we'll go to some store to buy some nice solution...and please..!..understand I am sure it'll be such a nice solution...but...(maybe you're getting tired of this question).."what about us? what about our part in these?..." we, ....professional people, students, and people who investigate cannot lose our part of this cake....

"is it happening without us?"

Well, maybe a few years ago it was such a crazy idea to think a person with his or her Pentium II could make an application to turn on the tv from the cell phone, ...well it could be done, but it was too hard for a single person or little team, ....because of the cost of technology, communications, tools, and information.....now,...now that's different....

With Visual Studio .NET 2005 mobile applications development has become much more easier,...to the point that it is just within a few clicks to have my own "hello world" on the internet ready to be downloaded to my cell phone or, when supported, my own "hola mundo" messagebox....

"Ok Javi..that's great....my 'ego' is satisfied....i have my own "hello world",...but what else?,...can i make something USEFUL?"

Sure we can! Let's says -for example- we want to turn on the lights when we are not at home so all the thieves can "see" there's somebody. How can I do that?...well, we could connect the lights to the computer at home,...and send bits to them through some port, so we can turn them on or turn them off. You can see how to do that in an article made by Tony Northrup. I think it's clear that we'll control the lights through some code we can access to through some operation; so..now we could create a Web Service that exposes that operation to the Internet. No Public IP Address???..well there are quite many solutions for that, check out www.noip.com for example,...so, now your Web Service is "online" you can consume it from your cell phone explorer (I use a Motorola RAZR) and turn on the light at home,....easy ah???...

...I know I'm dismissing many technical but all I've talked about here is not something you can't get to know with a few hours of reading and investigating,...so I dare you to move and try on what is new on technology, .....nowadays we have very good tools (VS.NET 2005 is awesome)....so,....let's create.....