Issuu on Google+

www.dotnetmania.com

nº 58 abril 2009 6,50 €

Visual Basic • C# • ASP.NET • ADO.NET • AJAX • Silverlight • .NET Framework

dotNetManía dedicada a los profesionales de la plataforma .NET

Entity Framework entrevista

Danny Simmons y Diego Vega Dev Manager y Program Manager Equipo de desarrollo de Entity Framework Microsoft Corp.

eventos

MIX 2009 Global MVP Summit 2009


editorial

dotNetManía Dedicada a los profesionales de la plataforma .NET Vol. III •Número 58 • Abril 2009 Precio: 6,50 €

Apuesta por el desarrollo Web

Editor Paco Marín (paco.marin@netalia.es) Redactor jefe Marino Posadas (marino.posadas@dotnetmania.com) Redacción Alberto Población, Guillermo 'Guille' Som, Luis Fraile, Luis Miguel Blanco, Miguel Jiménez y Miguel Katrib (Grupo Weboo) Empresas colaboradoras Alhambra-Eidos Krasis Plain Concepts Raona Solid Quality Mentors

Además colaboran en este número César de la Torre, Guillermo de la Torre, Isabel Gómez, Octavio Hernández y Unai Zorrilla. Diseño y maquetación Silvia Gil (Letra Norte) Atención al suscriptor Pilar Pérez (pilar.perez@netalia.es)

Edición, suscripciones y publicidad

.netalia c/ Robledal, 135 28522 - Rivas Vaciamadrid (Madrid) www.dotnetmania.com

Tf. (34) 91 666 74 77 Fax (34) 91 499 13 64 Imprime Gráficas MARTE ISSN 1698-5451 Depósito Legal M-3.075-2004

Bienvenido al número 58, de abril de 2009, de dotNetManía. Sin lugar a dudas, el evento más importante y esperado desde el PDC era el MIX 2009, celebrado recientemente en Las Vegas. En él se han presentado muchas novedades, tales como: la primera beta de Silverlight 3, que permitirá la reproducción de vídeo en alta definición a pantalla completa, en directo y bajo demanda, con la compatibilidad con el formato H.264; la versión preliminar de Expression Blend 3, diseñada para mejorar la productividad y los flujos de trabajo entre diseñadores y desarrolladores, que permitirá importar directamente archivos de Adobe Photoshop e Illustrator; diversos componentes de la Plataforma Web de Microsoft, entre los que se encuentra Web Platform Installer 2.0 Beta, una herramienta que simplifica la instalación y actualización de diversos productos para la Web, o Windows Web Application Gallery, que permite a los desarrolladores descargar aplicaciones y componentes gratuitos que les ayuden a crear aplicaciones Web o subir los suyos propios; el esperado Windows Internet Explorer 8, con nuevas posibilidades para los desarrolladores Web como los aceleradores y web slices; y, finalmente, una actualización significativa de la Plataforma de servicios Azure. Puede leer la información completa en la sección de noticias, y también en la crónica del evento que hace Miguel Jiménez, quien también cubrió el evento Global MVP Summit 2009, el encuentro anual entre sus grupos de producto y los MVP de todo el mundo, celebrado en Seattle. El apoyo al desarrollo de aplicaciones Web y a los servicios online que ofrece Microsoft es algo constatable, incluso localmente, de lo que dan muestra fehaciente los últimos proyectos puestos en marcha en esa línea. El más reciente es MSDN Respuestas, un add-in desarrolla-

do por Microsoft Ibérica que hará que podamos realizar búsquedas de soluciones a nuestros problemas desde el propio Visual Studio incluso entre los foros de Microsoft o las comunidades de desarrolladores. Repasamos cada iniciativa tomada localmente también desde las páginas de actualidad de este mes. El ejemplar de este mes está centrado casi monográficamente en Entity Framework, ahora que este marco de trabajo ha alcanzado la madurez suficiente —las empresas ya lo están utilizando y empieza a haber abundante documentación sobre él—. La coordinación técnica de este especial ha corrido a cargo de Unai Zorrilla, coautor junto con Octavio Hernández y Eduardo Quintás del libro “ADO.NET Entity Framework. Aplicaciones y servicios centrados en datos” (editado por Krasis en perfecto castellano), y coautor de la serie de artículos “El Marco de Entidades de ADO.NET 3.5” que venimos editando desde hace tiempo en dotNetManía. Puede leer un resumen de lo publicado este mes en el artículo de presentación que Unai mismo ha escrito. Adicionalmente, quiero presentarle a Alberto Población, que a partir de este mes se hará cargo de la sección de preguntas y respuestas. Alberto está muy involucrado en todo lo que tiene que ver con la ayuda a los miembros de la comunidad que la necesiten. En los foros y grupos de noticias de C# y otras tecnologías .NET, todo el mundo le conoce por su buen hacer. Esta sección resumirá cada mes lo mejor de la experiencia de Alberto en la resolución de problemas frecuentes a los que se enfrentan los desarrolladores. No puedo terminar estas notas sin antes agradecer públicamente a Dino Esposito —anterior titular de la columna—, por el gran trabajo realizado durante los últimos años. Mil gracias, Dino. Espero que el ejemplar sea de su agrado. Paco Marín


sumario 58 Eventos

10-13

MIX 2009 y Global MVP Summit

Especial Entity Framework

14-15

Pasados varios meses desde la aparición oficial de este innovador marco de trabajo como parte de .NET Framework 3.5 SP1 y Visual Studio 2008 SP1, y una vez que numerosas empresas han comenzado a utilizarlo y que ha aparecido abundante documentación sobre él, pensamos que un ejemplar así sería de utilidad a todos los lectores.

Entrevista a Danny Simmons y Diego Vega

16-19

El pasado 3 de marzo, en el marco del Microsoft MVP Summit 2009, nuestros colaboradores Unai Zorrilla y Octavio Hernández tuvieron la oportunidad de entrevistar a Danny Simmons y Diego Vega, Dev Manager y Program Manager, respectivamente, del equipo que desarrolla Entity Framework en Microsoft.

Presente y futuro de ADO.NET Entity Framework

20-24

La primera versión de Entity Framework, que apareció junto con Visual Studio 2008 SP1, venía provista de capacidades muy potentes, tanto a nivel de herramientas (diseñador visual, generador de código, etc.) como a nivel del entorno de ejecución (Entity Client, Servicios de objetos, LINQ to Entities, etc.), tal y como hemos visto en artículos anteriores. En la próxima versión de Entity Framework y de Visual Studio se van a incluir nuevas características que van a implicar mejoras notables en productividad, en extensibilidad y en flexibilidad. A lo largo de este artículo vamos a presentar algunas de ellas.

Manipulación de datos en Silverlight mediante ADO.NET Data Services (I)

26-30

La evolución en el desarrollo de aplicaciones Web hacia modelos en los que la parte cliente (AJAX, Silverlight) está dotada de una mayor inteligencia y programabilidad está propiciando que la arquitectura de estas aplicaciones se base, cada vez más, en servicios, fundamentalmente en lo relativo a las operaciones de acceso y manipulación de las fuentes de datos utilizadas por la aplicación.

Consulta de modelos conceptuales con Entity SQL (III) Los métodos de construcción de consultas

32-35

Este mes dedicamos esta columna a los métodos de construcción de consultas de los Servicios de objetos de Entity Framework, un tema que se tocó muy ligeramente en la primera entrega y que puede ser muy útil a la hora de implementar consultas parametrizadas y dinámicas sobre modelos conceptuales.

Implementación de un Membership Provider basada en ADO.NET Entity Framework

36-44

En este artículo se analiza SqlMembershipProvider, el proveedor de membresía (pertenencia) de ASP.NET para SQL Server, y se propone una implementación funcionalmente similar a la de este proveedor, pero basada en ADO.NET Entity Framework.

Entity Framework en aplicaciones con arquitectura N-Tier y N-Layer

46-52

ADO.NET Entity Framework, que es parte de .NET Framework a partir de la versión 3.5 SP1, es una plataforma de acceso a datos que hace transparente para el desarrollador el sistema gestor de bases de datos al que ataca (SQL Server, Oracle, etc.). El objetivo de este artículo es muy práctico: responder a la pregunta ¿cómo podemos utilizar Entity Framework en aplicaciones con arquitectura N-Tier o N-Layer?

dnm.q&a

53-56

Herencia de controles en Windows Forms

dnm.biblioteca.net

57

Programming Entity Framework de Julia Lerman (O'Reilly Media) Professional ADO.NET 3.5 with LINQ and the Entity Framework de Roger Jennings (Wrox)

dnm.desvan

58


<<dotNetManía

noticias noticias noticias noticias

noticias

6

Microsoft desvela nueva tecnologías para la Web en MIX '09 En el marco del MIX ‘09 celebrado recientemente en Las Vegas, Microsoft anunció un conjunto de nuevas inversiones para ayudar a las empresas a relacionarse con sus clientes de una manera más eficiente a través de una presencia en la Web más rica e interactiva. Entre las nuevas herramientas anunciadas destacan Microsoft Silverlight 3 Beta y Expression Blend 3 Preview, así como una actualización a la plataforma de servicios de Windows Azure para el desarrollo en la nube. Un anuncio importante fue la elección de Silverlight por parte de la empresa NBC Universal para ofrecer los próximos Juegos olímpicos de invierno, a celebrarse en Vancouver, a través de su sitio Web, NBCOlympics.com.

Novedades en Silverlight 3 Beta Silverlight 3 potencia a los desarrolladores Web para crear las mejores experiencias posibles para sus clientes a través del desarrollo de aplicaciones Web de última generación. Silverlight 3 ayuda a crear aplicaciones RIA (Rich Internet Applications), permitiendo trabajar más rápidamente con nuevas características gráficas, de animación y 3D, y más de 60 controles. Silverlight 3 también promueve una nueva generación de experiencias relacionadas con el vídeo, a través del uso de vídeo de alta definición a pantalla completa, en directo y bajo demanda, y nuevas opciones de formato, incluyendo H.264. Otra novedad importante es deep linking, característica orientada a mejorar la navegación por el contenido Silverlight y automatizar las tareas de optimización de motores de búsqueda. Finalmente, Silverlight 3 permite a los desarrolladores crear experiencias de aplicaciones Web ligeras fuera del navegador, lo que permitirá a los sitios Web esta-

blecer relaciones más persistentes con sus clientes.

Novedades en Expression Blend 3 Preview Microsoft también presentó una versión preliminar de Expression Blend 3, diseñada para mejorar drásticamente la productividad y los flujos de trabajo entre diseñadores y desarrolladores. Durante el evento, Microsoft mostró SketchFlow, una nueva característica que permitirá a los diseñadores hacer prototipos rápidos del flujo y la composición de aplicaciones. Por primera vez, los diseñadores podrán recibir feedback anotado directamente sobre sus prototipos, e iterar rápidamente desde el concepto hasta su implementación final. Adicionalmente, Expression Blend soporta directamente la importación de archivos de Adobe Photoshop e Illustrator, la integración directa de datos de ejemplo y un conjunto completo de comportamientos ricos.

Acceso más fácil a herramientas, plataformas y aplicaciones Microsoft también liberó durante el evento diversos componentes de la Plataforma Web de Microsoft, un conjunto integrado de herramientas, servidores y marcos de desarrollo que funcionan conjuntamente e interoperan con aplicaciones y productos open source utilizados por la comunidad. Parte de esta plataforma es Web Platform Installer 2.0 Beta, una herramienta que simplifica la instalación y actualización de los productos para la Web y otros componen-

tes Web gratuitos de Microsoft. Esta versión permite a los usuarios descargar tanto PHP como la versión final de ASP.NET MVC 1.0. Microsoft también lanzó Windows Web Application Gallery, que permite a los desarrolladores descubrir, explorar y descargar aplicaciones y componentes que les ayuden a crear aplicaciones Web. Los desarrolladores pueden subir a esta galería aplicaciones gratuitas, lo que les dará la posibilidad de conectar con millones de otros desarrolladores Web y promover sus soluciones. Asimismo, la galería incluye enlaces a aplicaciones populares, como Drupal, DotNetNuke y WordPress. Finalmente, Microsoft también anunció la disponibilidad de Microsoft Commerce Server 2009, que permite a los negocios crear experiencias de comercio electrónico mejoradas.

Aumentando las inversiones en la nube con la Plataforma de servicios de Azure Además de las inversiones destinadas a mejorar las experiencias de interfaz de usuario, Microsoft presentó sus inversiones en la plataforma de back-end, a través de las actualizaciones a la plataforma de servicios Azure. Durante el evento se presentaron nuevas posibilidades en Windows Azure, incluyendo el soporte de confianza total para aumentar el nivel de flexibilidad para los desarrolladores mediante la posibilidad de acceder al código nativo o utilizar lenguajes no-.NET a través de FastCGI, y el aprovechamiento de la geolocalización para alojar datos y código a lo largo de diferentes centros de datos, lo que permitirá a las empresas asegurar la continuidad del servicio y mejorar el rendimiento gracias a una menor latencia.


<< dnm.directo.noticias Internet Explorer 8 ofrece nuevas posibilidades a los desarrolladores Web También en el marco de MIX '09, Microsoft anunció la disponibilidad global de Windows Internet Explorer 8, que ofrece un rendimiento superior, herramientas de desarrollo Web que harán posible experiencias de navegador mejoradas, y gran seguridad y fiabilidad. En su presentación del producto, Dean Hachamovitch, responsable del equipo que lo desarrolló, mostró soluciones de partners como ESPN, eBay o Facebook que crean nuevo valor para sus clientes.

Nuevas oportunidades para los desarrolladores Los desarrolladores se beneficiarán de las nuevas características de rendimiento que permitirán a usuarios de los sitios Web acceder mucho mejor a los contenidos. Los aceleradores y web slices facilitarán a los desarrolladores ir más allá de la página y ofrecer nuevas vías para que la gente se mantenga conectada a los contenidos y servicios de su elección. Internet Explorer 8 ofrece capacidades de búsqueda mejoradas y otras posibilidades para ofrecer contenido más relevante e interesante, mayor velocidad de navegación, y una mejor seguridad y fiabilidad.

Compromiso con los estándares y herramientas integradas Internet Explorer 8 es el navegador de Microsoft que cumple más cabalmente

con los estándares hasta el momento, y aprovecha el trabajo conjunto de Microsoft con los organismos de estandarización para una mayor consistencia. Como parte del compromiso de Microsoft de dar soporte a los estándares, la empresa envió más de 7.000 escenarios de pruebas de CSS 2.1 al consorcio W3C durante el año pasado para ayudar a una adopción más sencilla y medible para todos los desarrolladores. Además, Internet Explorer 8 pasa más casos de prueba de CSS 2.1 que ningún otro navegador, y ha invertido recursos significativos en el soporte para HTML 5. El funcionamiento por defecto en modo compatible con los estándares y la existencia de una Vista de compatibilidad para facilitar la transición permitirán a los desarrolladores asegurarse de que su código funciona en múltiples plataformas y navegadores. Finalmente, mediante la incorporación de Internet Explorer Developer Toolbar directamente en Internet Explorer 8, Microsoft permitirá a los desarrolladores depurar fácilmente HTML, CSS y JavaScript. Estas capacidades mejoradas potenciarán a los desarrolladores para ofrecer mejores experiencias Web a sus clientes. Para obtener más información y descargar Internet Explorer 8, visite http://www.microsoft.com/ie8. Encontrará más información relacionada con el desarrollo en http://www.msdn.microsoft.com/ie.

Microsoft Surface llega a España Microsoft Surface permite interactuar con la información digital a través del tacto, gestos naturales de la mano e incluso colocando objetos físicos sobre la pantalla

Microsoft Surface es un dispositivo que pertenece a una nueva categoría que supone el paso de las interfaces gráficas a las interfaces naturales de usuario. Para dotarle de contenido y aplicaciones, se cuenta con el aporte de un robusto ecosistema de desarrolladores y partners. Más de 120 partners en 11 países diferentes ofrecen actualmente o están ideando nuevas aplicaciones para Microsoft Surface. En España, empresas como Plain Concepts ya están trabajando en el desarrollo de aplicaciones para este dispositivo. Como explica María Garaña, presidenta de Microsoft Ibérica, “Surface es una categoría completamente innovadora que responde a un enorme esfuerzo inversor de Microsoft y a su firme creencia en que se está gestando un cambio drástico en nuestra relación con la tecnología. Tenemos un fuerte compromiso a largo plazo con esta línea de negocio, que supone un aporte de valor sin precedentes para ayudar a optimizar el negocio de nuestros clientes con sus usuarios y contribuir a que nuestros partners creen contenidos y soluciones de negocio rompedoras a la vez que imposibles de desarrollar con otras tecnologías”.

Microsoft ha anunciado cómo los desarrolladores pueden diseñar y vender sus nuevas aplicaciones para teléfonos Windows –los novedosos teléfonos con Windows Mobile 6.5 y los nuevos servicios móviles de Microsoft– a través de su tienda online de aplicaciones Windows Marketplace for Mobile. Todos los desarrolladores de aplicaciones para teléfonos Windows que distribuyan sus programas a través de Marketplace obtendrán el 70% de los beneficios de las ventas. Para colocar sus aplicaciones en Marketplace, los desarrollado-

res tendrán que abonar una suscripción anual de 99 dólares que les dará derecho a subir hasta cinco aplicaciones. Cada aplicación adicional que se quiera subir durante ese mismo periodo de tiempo costará otros 99 dólares. La suscripción será gratuita para los desarrolladores que sean estudiantes y que formen parte del programa DreamSpark. Con Windows Marketplace for Mobile, que estará disponible en 29 países, los desarrolladores dispondrán de una amplia base de clientes internacionales. Además, Microsoft va a trabajar de

manera ininterrumpida con los desarrolladores para asegurarse de que todas las aplicaciones que estén disponibles en Marketplace funcionen perfectamente con los nuevos teléfonos Windows y de que hayan pasado un riguroso control de certificación y un proceso de prueba. Los desarrolladores tendrán acceso a todos los detalles sobre el registro de sus aplicaciones en la tienda online durante esta próxima primavera y podrán comenzar a subirlas en verano. Para más información, visite el sitio: http://developer.windowsmobile.com.

<<dotNetManía

Microsoft desvela su estrategia para los desarrolladores para la próxima generación de teléfonos Windows

7


<< dnm.directo.noticias

Servicios online de Microsoft para la comunidad de desarrolladores Microsoft Ibérica ha presentado de forma unificada sus nuevas iniciativas para trabajar con todas las comunidades técnicas en España. La compañía está invirtiendo mucho en la creación y mantenimiento de los servicios online para la comunidad de desarrolladores, y fruto de ello es el espectacular incremento experimentado por el tráfico de MSDN en español, con un crecimiento entre el 300% y 400% del número de visitas de los desarrolladores de habla hispana. Además, un dato que refleja la calidad del contenido es el tiempo medio de permanencia, que es de alrededor de 10 minutos.

Extender a otras tecnologías

<<dotNetManía

PureCode Actualmente, en el portafolio de herramientas de Microsoft ya empieza a haber componentes que pueden ser usados por otras tecnologías, como por ejemplo Silverlight, así como a ofrecer servicios en la nube, consumibles igualmente desde otras tecnologías. Por ello, y como primera propuesta concreta, Microsoft presentó el portal Pure Code (http://msdn.microsoft.com/eses/purecode), que ofrece a los desarrolladores de otras tecnologías como PHP y Java la ayuda y las guías necesarias para conseguir una mayor interoperabilidad de las herramientas Microsoft con estos entornos. Pure Code es una vista a la gran cantidad de recursos que se generan tanto en MSDN como en las comunidades de desarrollo, tales como vídeos, artículos, tutoriales, cursos online gratuitos, etc.

8

Portal de Open Source para desarrolladores Además, existe el portal de Open Source de Microsoft (http://msdn.micro soft.com/es-es/opensource y http://www.microsoft.com/opensource), dedicado tanto a los que quieren usar componentes de código abierto como a los que quieren desarrollarlos. Para los primeros, el portal ofrece ayuda para seleccionar e implantar componentes o soluciones completas. Estos componentes provienen de Microsoft –en CodePlex (http://www.code plex.com) hay más de 400– y también de otros partners; para los segundos, desde CodePlex se proporcionan diversas herra-

mientas de Microsoft que, además de repositorio, sirven para aportar herramientas para los que desarrollan.

Crear una experiencia más completa MSDN Respuestas MSDN Respuestas es un complemento innovador para Visual Studio, desarrollado desde Microsoft Ibérica, que permite encontrar la información que el desarrollador necesita mientras está trabajando, desde el propio entorno, e integrando múltiples fuentes de información como la referencia de MSDN, los principales buscadores, sitios Web de desarrollo y las respuestas más populares a las consultas que realices. La gran ventaja de este addin está en la especialización y la fiabilidad de las búsquedas en distintas fuentes. La especialización, porque buscará en sitios como en los propios foros o los sitios Web de desarrollo de mayor audiencia; la fiabilidad se conseguirá gracias a que el sistema permitirá votar por las respuestas obtenidas, de manera que la propia comunidad mejorará los resultados, permitiendo al sistema sugerir respuestas que otros desarrolladores han encontrado útiles para un problema determinado. MSDN Respuestas requiere Visual Studio Standard o superior, en tanto que la versión Express no permite instalar addins; pero posiblemente se ponga en marcha este mismo sistema fuera de Visual Studio, a través de una página Web. Para más información y descargas, visite el sitio Web http://msdn.microsoft.com/es-es/msdnrespuestas.aspx. Channel 9 Recientemente se ha puesto en marcha la versión en castellano del archiconocido Channel 9 (http://channel9.msdn. com/spain), lo que se enmarca dentro de las iniciativas para la mejora de los servicios online a los desarrolladores. A este portal no solo contribuyen personas de Microsoft, sino también algunos MVP y colaboradores cercanos, y es una buena

forma para Microsoft para estar en contacto con una comunidad tan grande como la de los desarrolladores de habla hispana. Actualmente, podrá encontrar más de 50 vídeos cortos con contenidos de interés para cualquier desarrollador. Foros Ya está disponible una nueva plataforma para los foros, que actualmente tienen más de 800.000 usuarios registrados aportando contenido (a nivel mundial), con más de 3.500 mensajes al día, y en los que Microsoft ha invertido una buena cantidad de recursos para garantizar que estén monitorizados, libres de spam y tráfico no deseado. Los foros son una de las vías preferidas por los desarrolladores para dar solución a muchos de sus problemas, y con MSDN Respuestas estarán aún más accesibles. La dirección es: http://social.msdn.microsoft.com/forums/es-es/categories.

Dar valor de negocio Ven&Gana El apoyo a empresas que están desarrollando sitios Web con tecnologías de Microsoft consiste en subvenciones en servidores Web dedicados, formación gratuita, soporte ilimitado gratuito, acceso preferente al software y actividades de generación de negocio. El proyecto es local y se llama Ven & Gana. Puede consultar toda la información en: http://msdn.microsoft.com/es-es/dd565831.aspx. BizSpark Para emprendedores con empresas de menos de 3 años de existencia y que estén facturando menos de 1 millón de dólares, Microsoft ha presentado el proyecto BizSpark, un proyecto a nivel internacional que aporta todo el software necesario para construir y explotar soluciones de forma gratuita. En España ya hay más de 100 empresas suscritas a BizSpark. El sitio Web es: http://www.microsoft.com/bizspark. Puede obtener más información sobre todo lo expuesto aquí en: http://www.microsoft.com/youshapeit/es/es/ msdn/Home.


eventos

eventos

MIX 2009

Es costumbre entre los devotos de la tecnología Web y la experiencia de usuario marcar en sus calendarios una visita anual a Sin City. No es que el juego y la lujuria sean un mal atractivo, pero es más bien la conferencia MIX lo que atrae a dicho público. Durante los días 18, 19 y 20 de marzo, en el ostentoso hotel The Venetian de Las Vegas, se celebró la 4ª edición de la conferencia de interacción, diseño y tecnologías Web de Microsoft.

<<

En un año marcado por el futuro lanzamiento de la nueva versión de Visual Studio, la conferencia prometía infinidad de novedades relacionadas con las aplicaciones ricas. Y no fue menos. La keynote del primer día sació las ansias de casi todos, pues comenzando con Bill Buxton (Microsoft Researcher y autor del libro “Sketching User Experiences“) y seguido por Scott Guthrie, se fueron anunciando nuevas versiones de productos casi cada minuto. Y no fueron pocas. En primer lugar, se anunciaron los platos fuertes de la conferencia, que han sido sin lugar a dudas Silverlight 3, Expression Blend 3 e Internet Explorer 8, todos incluyendo una amplísima lista de nuevas características, SDK asociados, documentación y cantidades de información imposibles de digerir en una única conferencia. Otras cosas no menos importantes desveladas durante esa keynote y luego presentadas con mayor detalle durante la conferencia fueron ASP.NET MVC 1.0, Microsoft Web Platform Installer, Microsoft Web Platform Gallery, Expression Web SuperPreview, Microsoft Trans-


lator y una actualización de Windows Azure. Al mismo tiempo, un extenso showcase de partners, entre los que podemos destacar a Netflix, KEXP y Bondi, entre otros, mostraba sus últimos avances en relación con dichas tecnologías. Con tanta novedad, la conferencia prometía salas abarrotadas en las sesiones de Silverlight, pero ¿quedaba algo más que decir para la keynote del segundo día? Por supuesto. Últimamente, y siguiendo el ejemplo de otras conferencias, las keynotes de Microsoft han pasado de ser simples charlas de apertura a convertirse en discursos de alto contenido inspirativo que se programan para cada día. De esta forma, la keynote del segundo día contaba con una de las historias más evocadoras en torno a User Experience que he escuchado desde hace mucho tiempo. De la mano de Scott Guthrie, Deborah Adler nos presentó el proceso creativo, centrado en usuarios y lazos emocionales, que la guió hacia la creación de ClearRX, un sistema de etiquetado y clasificación de medicamentos para la marca Target. Está claro eso que tiene más bien poco que ver con el diseño de software, pero tal y como decía Bill Buxton en su presentación, “no estamos diseñando bicicletas; diseñamos la sensación de montar en bicicleta“, algo muy importante a la hora de crear productos de software: tan importante es el producto y su función como la manera en que será utilizado. Con respecto a los espacios disponibles, aunque se ha incrementado el número de sesiones en la conferencia también se han disminuido los goodies físicos típicos de la misma; por ejemplo, ya no hay masajes para los asistentes, pero ahora pueden jugar al ping-pong. Este año se celebró, nuevamente, un concurso de “Rock Band“, y como hito especial, se proyectó “Objectified“, el nuevo documental de Gary Hustwit (director del aclamado “Helvetica“), junto a una ronda de preguntas y respuestas con el director. La fiesta de asistentes se celebró en el restaurante asiático Tao, dentro del mismo hotel, y reunió a todos los miembros de los grupos de producto junto a los asistentes del evento. Bueno, pero ¿y las sesiones? Una de las únicas pegas de esta edición de MIX, en mi opinión, es que estuvo muy floja en cuanto a temas de interacción y experiencia de usuario. A pesar de que en ambas keynotes se hizo una amplia referencia a esos temas, esto no se vio reflejado luego en la programación de las sesiones. La charla de Corrina Black (“User Experience Design Patterns for Business Applications with Microsoft Silverlight 3“) y la de Peter Eckert (“Escaping Flatland in Application Design: Rich User Experiences“) fueron los principales aportes en ese ámbito, mientras que el resto de sesiones de la conferencia estuvieron dedicados, mayoritariamente, a Silverlight, ASP.NET, ADO.NET y SQL Server Data

Services y RIA Services, como puede leer en la sección Noticias de este mismo ejemplar. De cualquier forma, el MIX sigue reuniendo a un público ávido de tecnología y deseoso de crear las mejores experiencias Web posibles, inspirado en el leitmotiv de la conferencia “The Next Web Now!”. Ahora solo nos queda esperar hasta el MIX ‘10, a celebrarse el próximo marzo de 2010, nuevamente en Las Vegas.

Texto: Miguel Jiménez

<<dotNetManía

<< dnm.directo.eventos

11


eventos

eventos

Global MVP Summit 2009

<<

Durante los días 1, 2, 3 y 4 de marzo, Microsoft Corporation celebró en Seattle el encuentro anual entre sus grupos de producto y los profesionales independientes galardonados con el reconocimiento MVP (Microsoft Most Valuable Professional), extendiéndolo hasta el campus de Redmond. Es curioso que en los tiempos que corren muchos de estos profesionales se decidiesen a asistir, un año más, para obtener información privilegiada; y no

es que la economía lo haya favorecido especialmente, pero sin duda ha sido un año bastante especial para los que hemos tenido la oportunidad de formar parte de esta experiencia. En un año marcado por las noticias de crisis y recesión, el MVP Global Summit 2009 estuvo guiado claramente por un énfasis en respetar el acuerdo de confidencialidad (NDA) que como “galardonados” tenemos con la compañía. Y sin duda alguna, este énfasis en el respeto estuvo bien respaldado por la cantidad de información que se nos ha proporcionado a todos los asistentes. Evidentemente, estas páginas no son una reseña sobre dichas novedades, lo que violaría dicho acuerdo, sino espacio para destacar las actividades que se han desarrollado y una posible opinión sobre la visión sobre Microsoft de sus MVP. El encuentro, al contrario que en ediciones anteriores, comenzó “al revés”, algo comprensible si lo evaluamos objetivamente, quedando para el último día la keynote con Steve Ballmer. El primer día de conferencia, domingo 1 de marzo, se celebró en el Washington State Convention Center (WSCC), y su principal foco fue el de unir a comunidades alrededor de los grupos de producto de una manera más informal, con sesiones paralelas de MVP Leads, User


Group Managers, INETA y similares. En lo que al castellano se refiere, tuvimos la oportunidad de contar con un miembro del equipo de Oslo, Miguel Llopis, que ofreció una sesión privada en nuestro idioma sobre esa novedosa tecnología para los MVP españoles y latinoamericanos. Un día lleno de posibilidades de networking entre pares que permitió, además, prepararse para la expedición del segundo día.

la posibilidad de asistir a pequeñas reuniones paralelas con un reducido grupo de asistentes. Tras el gran esfuerzo dedicado a los grupos de producto, otra exclusiva oportunidad de networking se presenta con la fiesta oficial del encuentro, que en esta ocasión se celebró a los pies del Space Needle, legado de la Exposición Internacional celebrada en la ciudad, en

el plato fuerte estaba por llegar. Un excitado Ballmer, como de costumbre, se zarandea, salta y grita por el escenario con la intención de generar una euforia similar en los asistentes; y funciona, el público grita a la par y sin motivo aparente la frase “We Love Windows 7” a las órdenes de Ballmer, para un posible remake del anuncio “I Am A PC”. Tras ofrecer la visión de la compañía, una típi-

El lunes 2 de marzo, los autobuses iniciaron temprano en la mañana rutas en los hoteles del centro de Seattle para llevar a los asistentes hacia Redmond, situado algunos kilómetros al este de la ciudad, y comenzar las intensas sesiones con los grupos de producto. Es un día curioso en el campus, pues muchos de los asistentes se desplazan al edificio que les corresponde, generalmente al del grupo de producto relacionado con su galardón, y existe una actividad efervescente por todos ellos que dota de una vida y dinamismo especial a las oficinas, salas de reuniones o auditorios. No obstante a ello, gran parte de las sesiones del primer día en el campus se celebraron en el Microsoft Conference Center, por contar éste con auditorios más grandes. Fue en este edificio, por ejemplo, donde tuvieron lugar las sesiones de C#, VB, ASP.NET o Silverlight. El tercer día de la conferencia, martes 3 de marzo, en lugar de ofrecer sesiones generales para proporcionar una visión global, favoreció una comunicación mucho más directa con los grupos de producto, sesiones más específicas y

la sala/museo EMP (Experience Music Project); el tema elegido fue la música. Aderezado con un poco de comida, los asistentes tuvieron la oportunidad de subir al escenario y mostrar sus dotes interpretativas a través de un karaoke con banda en directo. Una interesante vertiente de las jam sessions de ediciones anteriores, pues no todo el mundo es capaz de tocar un instrumento y formar parte de la experiencia. La noche, como es costumbre en Estados Unidos, acabó temprano, y preparó el camino para un dulce sueño justo antes de las keynotes de la conferencia. Miércoles, 4 de marzo: el desayuno se sirve una vez más en el WSCC y por megafonía se anuncia la apertura de la sala principal que alojará las keynotes. Tiempo de dejar la comida y correr a buscar un sitio privilegiado para las “sorpresas” prometidas. Tras una introducción al programa MVP por parte de Toby Richards, se empiezan a presentar novedades centradas en Windows 7, Visual Studio y todo el abanico de herramientas de diseño y desarrollo de la mano de Mike Nash y Soma Somasegar, pero

ca ronda de preguntas con el público se convirtió en lo mejor de toda la keynote. Quejas de los usuarios de SharePoint y promesas de Ballmer de atajarlas personalmente, publicidad de Windows Home Server directamente sobre su cabeza y peticiones de fotos en directo sobre el escenario fueron algunos de los acontecimientos que tuvieron lugar durante dicha ronda. Tal y como comentaba al principio, no estaba muy claro si la situación económica afectaría al encuentro de alguna forma, pero finalmente parece ser que únicamente el efecto se ciñó a minimizar los costes de alojamiento, emparejando a los asistentes en habitaciones. Esperemos que la situación mejore para el próximo año y que, al contrario de los rumores que corrían por las instalaciones, disfrutemos de una edición 2010 del MVP Global Summit con muchas más novedades para esta gran industria en la que trabajamos.

Texto y fotografías Miguel Jiménez

<<dotNetManía

<< dnm.directo.eventos

13


entity framework Unai Zorrilla

especial

Entity Framework

Unai Zorrilla es Development Team Leader de Plain Concepts. MVP desde 2004, colabora activamente con Microsoft en eventos de arquitectura y desarrollo, así como en giras de productos. Autor de los libros “Modelando procesos de negocio con Workflow Foundation” y “ADO.NET Entity Framework: Aplicaciones y servicios centrados en datos”.

Bienvenidos amigos, a este especial de dotNetManía sobre ADO.NET Entity Framework! Pasados varios meses desde la aparición oficial de este innovador marco de trabajo como parte de .NET Framework 3.5 SP1 y Visual Studio 2008 SP1, y una vez que numerosas empresas han comenzado a utilizarlo y que ha aparecido abundante documentación sobre él (consulte las referencias al final de esta presentación), pensamos que un ejemplar así sería de utilidad a todos los lectores.

<< Sin duda alguna, el surgimiento de Entity Framework (EF)

ha supuesto un cambio en la forma de pensar de muchos programadores, incluso a pesar de que en su primera versión quizás haya escenarios no cubiertos completamente. Por primera vez, disponemos de forma integrada en .NET y Visual Studio de capacidades reales para empezar a pensar en guiar nuestros desarrollos por modelos de dominio, que tanto se han popularizado a partir de los trabajos de Eric Evans y otros gigantes (cuyos consejos, por cierto, se han tenido muy en cuenta durante el desarrollo de la siguiente versión, como podrá leer en la entrevista de este mes). Con respecto a las herramientas integradas en VS 2008 SP1, Entity Data Model (EDM) nos aporta múltiples características para eliminar la impedancia que los programadores orientados a objetos sufrimos normalmente con respecto a los modelos relacionales implementados por los profesionales de bases de datos. Entre las capacidades más destacadas del diseñador de entidades podemos destacar la posibilidad de modelar distintos tipos de herencia (Herencia por Jerarquía, Herencia por Subtipo o Herencia por Tipo Concreto) o la representación de las relaciones en las bases de datos como asociaciones de clases (incluyendo el soporte de asociaciones muchos-a-muchos). Por supuesto, aún queda un poco de camino que recorrer para soportar otros escenarios habituales dentro de los modelos relacionales existentes hoy en día en distintas aplicaciones: aspectos como el uso de tipos complejos o el soporte para las claves solapadas (overlapped keys) son capacidades que se incorporarán en las siguientes versiones. En relación con esto, en este número especial Isabel Gómez (Microsoft DPE) escribe un excelente artículo, “Presente y futuro de EF”, con información de primerísima mano sobre las novedades que EF incluirá en la siguiente versión de Visual Studio, que tendremos liberada no dentro de mucho. También encontrará muchas ideas al respecto en la entrevista de este mes, que nos concedieron gentilmente dos de los líderes del equipo que desarrolla la tecnología en


<< dnm.entityframework

Microsoft, Danny Simmons (Dev Manager para EF y LINQ to SQL) y Diego Vega (Program Manager de EF). En cuanto al cambio en nuestra forma de desarrollar, EF nos permite incrementar de una manera sensible la productividad mediante la posibilidad de utilizar una implementación del patrón LINQ sobre los modelos de entidades, gracias a lo cual nuestro trabajo se hace fuertemente tipado, lo que sin duda alguna promueve una programación más eficiente y menos propensa a errores. Pero, por supuesto, EF no nos obliga a casarnos con LINQ to Entities para realizar nuestras consultas: también tenemos la posibilidad de utilizar los tradicionales procedimientos almacenados y de materializar automáticamente los resultados en las entidades definidas en el modelo, o de expresar directamente las consultas, por diferentes vías, mediante Entity SQL (eSQL), un subdialecto de SQL agnóstico del motor de bases de datos; una de estas vías, basada en el uso de los métodos de construcción de consultas (eSQL Builder Methods), es la que exploramos en nuestra entrega de este mes mi compañero de fatigas, Octavio Hernández y yo mismo. Por supuesto, tal y como ya hemos comentado anteriormente, ninguna primera versión de un producto fue completa, y EF no iba a ser una excepción a esta regla que parece inmutable en el mundo del software. La mayoría de la gente que interroga sobre esta tecnología en eventos de

divulgación, charlas de grupos de usuarios y/o procesos de formación, pone de manifiesto sus preocupaciones, dudas o problemas de implementación en aplicaciones distribuidas, donde las entidades consultadas viajan a través de una fachada de servicios. Por regla general, estas dudas son planteadas por desarrolladores que han hecho uso anteriormente de facilidades como las que objetos como los DataSet, con sus diffgram, ofrecen para mantener la gestión de los cambios que sobre ellos se producen, y tienen que ver con cómo hace EF esa gestión de los cambios ocurridos sobre las entidades que viajan a través de las diferentes capas de la aplicación. Sobre este tema, nuestro amigo César de la Torre (Microsoft DPE) nos presenta aquí su artículo “EF en aplicaciones con arquitecturas N-Tier y N-Layer”, en el que presenta los posibles enfoques que podemos adoptar e implementa completamente uno de ellos. Pero aún hay mucho más en este especial. Nuestros amigos al otro lado del Atlántico, miembros del Grupo WebOO de la Universidad de La Habana, nos presentan su implementación de un proveedor de ASP.NET Membership basado íntegramente en EF, que pone a nuestra disposición un sistema de control de pertenencia capaz de funcionar para múltiples bases de datos. Además, nuestro redactor Luis Miguel Blanco nos ofrece la primera entrega de una serie en la que mostrará cómo desarrollar clientes RIA de Silverlight que se conecten bajo demanda a la capa de

Desde aquí le animamos a probar y usar EF, un marco de trabajo que sin duda alguna ha llegado para quedarse

acceso a datos utilizando ADO.NET Data Services, otra importante nueva tecnología basada en EF. Espero sinceramente que el ejemplar que tiene en sus manos sea de su agrado. Para finalizar, no me gustaría dejar pasar esta oportunidad para animar a todos los que aún no lo han hecho a probar, investigar y usar EF, un marco de trabajo que sin duda alguna ha llegado para quedarse. Como comentábamos al principio, actualmente ya existen numerosos recursos disponibles en la red y se han publicado diversos libros, el primero de ellos, “ADO.NET EF. Aplicaciones y servicios centrados en datos” [2], escrito en nuestra lengua madre por españoles enamorados de esta tecnología desde sus primeras betas: Octavio Hernández, Eduardo Quintás y un servidor.

[ 1]

Zorrilla, U., Hernández, O., “El Marco de Entidades de ADO.NET 3.5” (I-VII), en dotNetManía nº 44-50, enero-julio de 2008.

[ 2]

Zorrilla, U., Hernández, O., Quintás E., “ADO.NET Entity Framework. Aplicaciones y servicios centrados en datos”, Krasis Press, 2008 (vea presentación de Marino Posadas en dotNetManía nº 55, enero de 2009).

[ 3]

Lerman, J. “Programming Entity Framework”, O'Reilly, 2009 (vea presentación de Marino Posadas en este mismo ejemplar).

[ 4]

Jennings, R. “Professional ADO.NET 3.5 with LINQ and the Entity Framework”, Wrox Press, 2009 (vea presentación de Marino Posadas en este mismo ejemplar).

<<dotNetManía

Literatura sobre EF

15


Unai Zorrilla, Octavio Hernández

Unai Zorrilla es Development Team Leader de Plain Concepts. MVP desde 2004, colabora activamente con Microsoft en eventos de arquitectura y desarrollo, así como en giras de productos. Autor de los libros “Modelando procesos de negocio con Workflow Foundation” y “ADO.NET Entity Framework: Aplicaciones y servicios centrados en datos”. Octavio Hernández es MVP de C# desde 2004, MCSD y MCT. Autor de los libros “C# 3.0 y LINQ" y “ADO.NET Entity Framework: Aplicaciones y servicios centrados en datos” (con Unai Zorrilla y Eduardo Quintás).

entrevista

entrevista a

Danny Simmons y Diego Vega El pasado 3 de marzo, en el marco del Microsoft MVP Summit 2009, nuestros colaboradores Unai Zorrilla y Octavio Hernández tuvieron la oportunidad de entrevistar a Danny Simmons y Diego Vega, Dev Manager y Program Manager, respectivamente, del equipo que desarrolla Entity Framework en Microsoft. En primer lugar, nuestro más sincero agradecimiento por esta oportunidad de entrevistaros para dotNetManía. Generalmente, nuestras entrevistas comienzan pidiendo a los entrevistados que se presenten brevemente ante los lectores de la revista. Diego Vega. Mi nombre es Diego Vega, y soy uno de los cuatro Program Manager del equipo de Entity Framework (en adelante EF). Normalmente mi trabajo se relaciona con los Servicios de objetos (Object Services)

y LINQ to Entities, y ocasionalmente también con LINQ to SQL. Danny Simmons. Yo soy Danny Simmons, Dev Manager del equipo que se encarga tanto de EF como de LINQ to SQL, y trabajo en Microsoft desde hace unos 12 años. ¿Y en qué proyectos trabajaste antes? Danny. Bueno, es una lista bastante larga. Empecé trabajando en el desarrollo de Outlook, luego en otro proyecto relacionado con


<< dnm.directo.entrevista

Queríamos felicitaros por el trabajo realizado con EF, que ha sido inspirador para muchos en la comunidad española de desarrolladores por el nuevo nivel al que eleva el desarrollo de aplicaciones centradas en datos, y que nos ha dejado expectantes de las posibilidades que se añadirán en la siguiente versión. Hemos seguido la iniciativa relacionada con el blog "EF Design", y queríamos preguntaros qué resultados ha producido. Danny. El blog "EF Design" ha sido un gran ejercicio para todos nosotros, tanto desde el punto de vista de hacernos reflexionar sobre las cosas que diseñamos de un modo diferente, en el sentido de permitirnos compartir las ideas por adelantado y estar en contacto con la comunidad, como desde otros puntos de vista sobre los cuales hemos recibido un excelente feedback. Por ejemplo, cuando liberamos por primera vez en el blog nuestras ideas y propuestas de API sobre el desarrollo en N capas, recibimos muchas sugerencias sobre la importancia de poder disponer de entidades con auto-seguimiento (self tracking entities); de manera similar, hay muchos otros casos en los que hemos introducido cambios positivos en el producto como respuesta a la actividad en ese blog. Lo otro que podría decir al respecto es que durante mucho tiempo hemos intentado estar lo más cerca posible de la comunidad, porque hay mucha gente con gran experiencia en este espacio y con diferentes puntos de vista sobre las maneras óptimas de actuar en diferentes escenarios, diferentes enfoques del mapeo objeto-relacional, y de quienes indudablemente podemos aprender mucho. Indudable-

mente, esta retroalimentación es un ejercicio muy saludable, incluso en los casos en que las ideas divergen sensiblemente de las nuestras. Diego. Me gustaría agregar que no siempre es fácil priorizar las diferentes tareas a acometer con vistas a pasar a la siguiente versión, y el feedback que obtenemos nos ayuda en gran medida a detectar cuáles son los principales aspectos problemáticos cuya solución es necesario priorizar. Desde aquí queremos estimular a toda la comunidad a seguir enviándonos sus sugerencias, que tienen en nosotros una influencia mucho mayor de la que seguramente sospechan. Mi trabajo como Program Manager se hace mucho más fácil gracias al aporte de la comunidad. ¿Qué podéis decirnos del aporte recibido de las personalidades que forman parte del llamado Consejo asesor, como Jimmy Nilsson o Martin Fowler? Danny. Hemos tenido discusiones sumamente productivas con los miembros del consejo, tanto con Nilsson y Fowler como con Eric Evans, Stephen Forte y Pavel Hruby. Por ejemplo, recientemente el equipo ha tenido un diálogo muy útil con Jimmy que nos ha aportado varias puntualizaciones importantes. En general, creo que algo muy positivo acerca de estas conversaciones fue el hecho de que no hubiera grandes sorpresas como resultado de ellas; ya contábamos con numerosos aportes de las comunidades a la que ellos representan, y habíamos oído muchas de las sugerencias que nos hicieron. Pero indudablemente, muchas de las ideas que ya nos rondaban se profundizaron y pulieron gracias a ellos, y además nos han dado otras perspectivas nuevas. En general, creo que hemos completado bastante el producto con estas ideas, y cuando ahora un miembro de la comunidad se nos acerca con una solicitud, generalmente se trata de que necesita que le ofrezcamos más rápidamente algo que ya tenemos en nuestra lista de cosas

pendientes. El problema es que EF es un producto grande, y las cosas tardan cierto tiempo en implementarse. En lo que respecta al desarrollo de aplicaciones centradas en datos, podríamos clasificar a los desarrolladores en dos grupos: los que intentan basarse más en un modelo conceptual y los que por una razón u otra obvian o minimizan ese proceso para centrarse directamente en los procesos de manipulación de datos que sus aplicaciones requieren. ¿Cómo podrá ayudar a ambas clases de desarrolladores la próxima versión de EF? Danny. Buena pregunta. Generalmente, yo intento dividir a los desarrolladores en varias categorías más, y no solo las dos que mencionas. En particular, añadiría un tercer grupo. Por un lado están, como dices, quienes intentan basarse en modelos conceptuales, y más concretamente en modelos de dominio; estos a la misma vez están muy centrados en el código y quieren tener un control total sobre él; para ellos son muy importantes cosas como Code First, POCO (Plain Old CLR Objects), etc., y tienden a ser "puristas" en lo relativo a la arquitectura. En el medio, hay un segundo grupo de desarrolladores a quienes les gusta en principio disponer de las características que ofrece EF, como el mapeo, etc., pero que están muy enfocados hacia una máxima productividad y lo que buscan del producto es principalmente una experiencia de herramientas y servicios que les permita hacer de una manera casi automática lo que hacían, por ejemplo, con datasets en versiones anteriores de .NET. Por último, está el grupo de gente que no está interesada en estas abstracciones y prefiere interactuar directamente con la base de datos. A estos últimos, no es mucho lo que EF les puede aportar; ciertamente, podrían crear modelos básicos, uno-a-uno, y utilizarlos con vistas a obtener un acceso fuertemente tipado a los datos, pero eso es lo mismo que obtendrían con LINQ to SQL

<<dotNetManía

Office que nunca vio la luz, pero que sentó las bases para lo que hoy es InfoPath, más adelante en Live Meeting, y también estuve un tiempo en Microsoft Business Solutions. Pero ya llevo más tiempo en este equipo del que nunca estuve en un mismo puesto anteriormente.

17


<<dotNetManía

<< dnm.directo.entrevista

18

o datasets tipados, y si realmente necesitan o simplemente desean un alto rendimiento probablemente preferirán trabajar directamente a más bajo nivel (DbDataReader, etc.) contra la base de datos. Creo que el grupo intermedio, el de los que quieren tener las abstracciones pero a la vez ser muy productivos, es el segmento en el que tenemos mayores oportunidades, porque lo que EF y sus herramientas asociadas les permitirán es ser muy productivos a la vez que crear algo que sea arquitectónicamente sólido y muy cercano a lo que se querría obtener si se desarrollara todo ese código manualmente a lo largo del tiempo. Porque, indudablemente, uno de los mayores peligros que han tenido otros enfoques anteriores del acceso a datos basados en programación visual, drag & drop y cosas así es que la aplicación comienza siendo manejable, pero a lo largo del tiempo se va convirtiendo en un pastiche inmantenible, que en cierto momento se hace necesario tirar para empezar de nuevo. Que es, por cierto, la vía a través de la cual muchos de los desarrolladores de este grupo intermedio se pasaron al primero: empezaron usando esas tecnologías, pero se frustraron y ahora intentan ser muy cuidadosos. No obstante, sigue habiendo una cantidad considerable de desarrolladores en ese grupo intermedio, además de la afluencia a él de nuevos desarrolladores, y lo que intentamos hacer es que puedan alcanzar ese punto ideal en el que obtengan una alta productividad evitando totalmente a su vez el engorro arquitectónico por debajo. Diego. Estamos trabajando mucho en lo relativo a intentar encontrar las abstracciones adecuadas sobre las bases adecuadas, y pienso que hemos hecho grandes progresos a ese respecto con vistas a la próxima versión. La conclusión clave es que una cosa no tiene por qué estar en contradicción con la otra: la corrección en la arquitectura no tiene necesariamente que estar reñida con la productividad.

Entity Framework permitirá a los desarrolladores ser muy productivos a la vez que crear software arquitectónicamente sólido

¿Podríais referiros brevemente a las principales novedades que incorporará la próxima versión de EF? Danny. Creo estas novedades se pueden categorizar en varios temas que han emergido claramente de todo el trabajo realizado a partir de la versión inicial. Uno de los temas engloba todo lo que tiene que ver con las maneras en las que el desarrollador puede ganar mayor control sobre su código; en este grupo podemos clasificar novedades como la posibilidad de utilizar entidades POCO, la disponibilidad de opciones a la hora de implementar una verdadera ignorancia de la persistencia (Persistence Ignorance), la integración del lenguaje T4 en las herramientas para permitir una mayor personalización de la generación de código, e incluso cosas como la incorporación de una nueva interfaz, IObjectSet<T>, para facilitar en gran medida el mocking y las pruebas en general. Otro gran tema es el relacionado con el desarrollo en N capas; se ha hecho una gran inversión para hacer mucho más fácil y efectivo el desarrollo de aplicaciones de múltiples capas con EF en una amplia gama de posibles escenarios. Un tercer gran tema tiene que ver con hacer más fácil la adopción de EF para los desarrolladores que utilizan LINQ to SQL, incorporando toda una serie de cosas que a la gente le gusta de LINQ to SQL, como la carga implícita demorada (impli-

cit lazy loading), operadores de consulta adicionales, o una experiencia similar en el uso de las herramientas visuales para los procedimientos almacenados. Un cuarto tema es el relacionado con la manera en que trabajamos, con los fundamentos, y en este sentido hay toda una serie de lugares dentro de EF en los que hemos trabajado para mejorar tanto la utilidad y usabilidad de las API como el rendimiento y la seguridad. Un pequeñísimo ejemplo de esto último puede ser el hecho de que el método ObjectContext<T>.SaveChanges es ahora virtual, lo que permitirá a los desarrolladores redefinirlo para una clase de contexto determinada. ¿Algo que se me olvide, Diego? Diego. El tema relacionado con los partners en general. Esto tiene que ver con un cierto trabajo de “preparación” de nuestras API que estamos llevando a cabo para facilitar la interacción de EF con otros marcos de trabajo; porque es muy grande el valor que pueden aprovechar de EF otros productos, como por ejemplo Reporting Services, así como el que puede obtener el propio EF, por ejemplo, de la utilización de las inversiones que se vienen realizando en Oslo. Danny. Adicionalmente, más allá de lo relacionado con EF en sí, hemos estado trabajando internamente en vías para mejorar nuestra velocidad de respuesta a las necesidades de los desarrolladores; en particular, para poder suministrarles valor de una manera incremental en ciertas circunstancias a un ritmo más rápido que el que ofrecen las versiones de .NET Framework y Visual Studio, pero siendo aún parte integral de .NET Framework. Tenemos algunos planes al respecto, que comunicaremos próximamente. Con tantos cambios y adiciones importantes, no nos quedará otro remedio que escribir un nuevo libro (risas). Danny. Efectivamente, ésta va a ser una actualización muy significativa de EF.


<< dnm.directo.entrevista

¿Cuáles son las diferencias principales entre los objetos POCO y los DTO (Data Transfer Objects) tradicionales? Diego. A diferencia de los DTO tradicionales, a los que no se les supone un comportamiento asociado, los objetos POCO generalmente sí lo tienen. Danny. Por ejemplo, uno podría querer tener diferentes conjuntos de comportamientos en la capa cliente y en la capa intermedia. Podría haber unas cuantas reglas de validación comunes a ambas capas, pero otra cantidad de cosas que se quisieran gestionar de manera

diferente, en particular cuando las entidades se hacen inteligentes. Algunos dirán que se podría incluir ese mínimo de validación en las entidades, e implementar todo lo demás en servicios externos, pero otros, y específicamente los practicantes de DDD (Domain Driven Design), prefieren hacer sus entidades muy inteligentes, que incluyan toda la lógica necesaria. Concretamente, Jimmy Nilsson recomienda construir un modelo de dominio para la capa intermedia y un modelo de dominio diferente para el cliente, porque los objetivos son diferentes, y enviar mensajes entre ellos. Por otra parte, un caso en el que yo recomendaría usar DTO es cuando existe lo que yo llamaría distintas frecuencias de cambio: cuando la frecuencia de cambio de mi modelo de dominio es diferente de la frecuencia de cambio del contrato de mi servicio. Por ejemplo, si comparto el servicio con un partner y no puedo controlar cuándo hace cambios en su código, pero no quiero tener que esperar por esos cambios para poder modificar mi modelo. Aunque tal vez en aquellos casos en que uno controla ambas capas (Silverlight es un gran ejemplo de esto –tengo mi capa intermedia y un cliente que se despliega cada vez que alguien lo ejecuta–), puede que no sea tan interesante tener clases diferentes; se podría tener objetos POCO compartidos en ambas capas, y esa sería una forma productiva y eficiente de trabajar para el desarrollador. La decisión de diseño depende, entonces, de si se controlan ambas capas y de las frecuencias con que las cosas cambian, además de, por supuesto, la lógica concreta. En el caso de las entidades con autoseguimiento, que hacen un seguimiento de sus propios cambios, ¿os habéis basado de alguna manera en un patrón similar a Active Record? Danny. Sí y no. Para la mayoría de la gente, el patrón Active Record está más cerca de lo que hace LINQ to SQL (mapeo uno-a-uno de las entidades con la base de datos, entidades muy parecidas

a las tablas de la base de datos, y luego puede que construyamos objetos de dominio que se conectan a las entidades). Podría establecerse una similitud entre esto y las entidades con auto-seguimiento en el sentido de que son segundas entidades que se parecen a las del modelo conceptual, pero, debido a que en EDM disponemos de la herencia y demás características avanzadas que conocemos, aquellas no se parecerán mucho a las tablas de la base de datos; eso hace que las entidades con auto-seguimiento se parezcan menos al patrón Active Record. Cuando aparecieron las primeras betas de EF, pensamos que EDM iba a ser una parte integral de prácticamente todas las tecnologías de acceso a datos de Microsoft, como Reporting Services, Business Intelligence, o incluso el Business Catalog de SharePoint. ¿Cómo está posicionado EF con respecto a otras tecnologías de la empresa como las antes mencionadas? Danny. Como ya mencionó antes Diego, hemos establecido conexiones con la mayoría de esos equipos, y en la visión de nuestra división de desarrollo EDM sigue siendo un posible factor unificador de todas esas diferentes tecnologías. El problema es que todas esas tecnologías constituyen productos establecidos, con una base de clientes existente, imposibilidad de hacer cambios que rompan la compatibilidad, etc. Así que se trata de un proceso lento. Con el que estamos comprometidos y en el que seguimos invirtiendo, pero lento. En los últimos tiempos hemos hecho un gran trabajo de integración con Reporting Services, cuyos resultados se verán en un futuro próximo; y hemos empezado a trabajar con otros grupos del equipo de SQL Server en ideas como incorporar EDM al catálogo del motor de bases de datos, entre otras. E interacciones similares las estamos llevando a cabo con los equipos de SharePoint, Master Data Management, el equipo de Workflow Foundation y otros.

<<dotNetManía

Habéis mencionado LINQ to SQL. ¿Podríais dejar claro a nuestros lectores cuál es la política oficial de la empresa acerca de este marco de trabajo? Danny. Este es un tema sobre el que sabemos que se habla mucho. Es muy importante que la comunidad sepa que LINQ to SQL no va a ser depreciado (deprecated), abandonado, ni nada por el estilo. Es una parte integral de .NET Framework y lo seguirá siendo; ninguna parte de .NET Framework desaparece de un día para otro. Y tampoco es nuestra intención que lo haga: queremos seguir dando soporte a los clientes que utilizan LINQ to SQL. Al mismo tiempo, como hemos dicho en otros fórums, EF es el marco de trabajo en el que estamos haciendo las inversiones estratégicas, por lo que la cantidad de nuevas funcionalidades que se incorporarán a EF es muy superior a la de las que se incorporarán a LINQ to SQL. Es un tema de prioridades a la hora de distribuir nuestros recursos. Pero también está un poco en correspondencia con lo que LINQ to SQL pretende ser: un marco de trabajo sencillo y fácil de usar, basado en un mapeo uno-a-uno de la base de datos, y específico para SQL Server. Añadiéndole muchas nuevas características a LINQ to SQL, podríamos estar perdiendo aquello que lo hace una gran herramienta para sus usuarios, y eso tampoco lo queremos.

19


entity framework

Isabel Gómez Miragaya

Presente y futuro de ADO.NET

Entity Framework La primera versión de Entity Framework, que apareció junto con Visual Studio 2008 SP1, venía provista de capacidades muy potentes, tanto a nivel de herramientas (diseñador visual, generador de código, etc.) como a nivel del entorno de ejecución (Entity Client, Servicios de objetos, LINQ to Entities, etc.), tal y como hemos visto en artículos anteriores [1]. En la próxima versión de Entity Framework y de Visual Studio se van a incluir nuevas características que van a implicar mejoras notables en productividad, en extensibilidad y en flexibilidad.A lo largo de este artículo vamos a presentar algunas de ellas.

Firma solidaria Isabel Gómez ha donado los derechos de autor de este artículo a la ONG Namaste, que busca mejorar la calidad de vida de los niños que habitan lugares con un entorno difícil. Desde Namaste se buscan soluciones locales a problemas locales, trabajando con organizaciones de cada país. Así, además de proporcionar los cuidados necesarios para el crecimiento de los niños, Namaste ofrece programas educativos adaptados a las necesidades de los niños de cada zona. Si está interesado en los proyectos de esta ONG o quiere ayudarles en su labor con estos niños, visite http://www.namasteong.es.Tam-

bién puede colaborar a través de la iniciativa “Un Clic solidario” en http://www.unclicsolidario.com. Isabel Gómez Miragaya es Evangelista de Desarrollo para fabricantes de software en Microsoft. Guía y asesora a los ISV en arquitectura y desarrollo con nuevas tecnologías.

Para una mejor comprensión, hemos dividido las características sobre las que vamos a hablar en dos grupos. Primero nos centraremos en las nuevas posibilidades asociadas a las herramientas de diseño incorporadas al entorno de desarrollo, para más adelante ocuparnos de las nuevas funcionalidades que nos ofrecerán las API que tendremos a nuestra disposición.

El futuro de las herramientas de Entity Framework Una de las mejoras más potentes relacionadas con el diseñador visual que estará incluida en Visual Studio 2010 es la posibilidad de personalizar fácilmente el código generado a partir del CSDL (definición del modelo conceptual) a través de plantillas personalizadas, partiendo si queremos de una serie de plantillas predefinidas que estarán "de serie" a nuestra disposición. El generador de código por defecto de Entity Framework (en adelante EF) (EntityClassGenerator) es el encargado de crear, a partir del fichero CSDL (contenido dentro del fichero EDMX generado por Visual Studio), el código con las correspondientes clases .NET que representarán nuestras entidades y las asociaciones entre las mismas, clases que actualmente quedan incluidas dentro de un fichero .Designer.cs o .Designer.vb. En la práctica, muy frecuentemente nos vemos en la necesidad de modificar el código generado para adaptarlo a nuestras necesidades. Algunos ejemplos frecuentes son marcar entidades o propiedades con atributos personalizados, implementar determinadas interfaces propias, etc. La forma de personalizar el código generado


<< dnm.entityframework

En Visual Studio 2010 se abre la posibilidad de usar plantillas de T4 para personalizar la generación de código a partir de modelos de entidades

aplicar las personalizaciones que desee. Visual Studio se encargará entonces de generar el correspondiente fichero de código a partir de esta plantilla. En la figura 1 podemos ver un ejemplo de personalización de la plantilla, en el que hemos especificado que la clase de contexto implemente una interfaz IValidate. Esta capacidad permitirá que el equipo de EF pueda, por ejemplo, liberar nuevas plantillas T4 fuera de los ciclos de salida de Visual Studio y de .NET con nuevas capacidades o correcciones. Pero no solo eso:

Figura 1. Plantilla T4 modificada (pantallazo de Clarius T4 Editor Community Edition for VS 2008)

<<dotNetManía

en la primera versión de EF pasaba por utilizar el mecanismo de extensibilidad estándar del SingleFileGenerator, lo cual resulta bastante tedioso y problemático, especialmente a la hora de personalizar o depurar. En Visual Studio 2010 se abre la posibilidad de usar plantillas de T4 para personalizar la generación de código y que además la experiencia esté totalmente integrada con el diseñador de entidades. T4, o mejor dicho, el “Text Template Transformation Toolkit”, es un motor de generación de código basado en plantillas. Está incluido con Visual Studio 2008 y Visual Studio 2010 (y es descargable para Visual Studio 2005 como parte de los toolkits de DSL y de GAT). Este motor puede usarse para generar código en C#, Visual Basic, T-SQL, XML o para generar cualquier fichero de texto como informes o páginas HTML. El mecanismo es sencillo: a partir de datos de entrada y la plantilla correspondiente (un archivo con extensión .tt conteniendo bloques de texto y lógica de control con una filosofía muy similar a ASP o cualquier lenguaje de macros), se genera el fichero o los ficheros resultantes. La forma de trabajar sería la siguiente. Seleccionamos el EDMX para el que queremos personalizar el código y añadimos al proyecto un nuevo elemento de Generación de Artefactos, concretamente el “ADO.NET EntityObject Generator”. Esto hará que se elimine el código generado por defecto (.Designer.cs o .Designer.vb) y se abra la plantilla .tt predeterminada. El desarrollador podrá modificar este fichero para

21


<< dnm.entityframework

Figura 2. Modelo conceptual con herencia entre entidades

<<dotNetManía

abrirá nuevas posibilidades hasta ahora no contempladas, como la posibilidad de crear plantillas que se integren con Visual Studio a través de la API EnvDTE para generar nuevos ficheros de proyecto o generar documentación HTML con las características de nuestro modelo conceptual. Podremos incluso empaquetar estas plantillas T4 en plantillas de elementos de proyecto de Visual Studio para que los usen los miembros de un equipo de desarrollo. Este mecanismo proporciona una vía fácil y potente de extensibilidad y personalización.

22

T4 también hará posible la utilización de una filosofía “El modelo primero”, una de las características más demandadas por la comunidad

Figura 3. Modelo relacional con esquema Tabla-por-Tipo

La próxima versión de EF usa T4 no solo para la generación de código, sino también para hacer posible la utilización en nuestros desarrollos de una filosofía El modelo primero (Model First), sin duda una de las características más demandadas por la comunidad. En la primera versión de EF, es necesario partir del esquema relacional de una base de datos para poder definir y mapear un modelo conceptual. Al añadir un nuevo modelo de EF a nuestro proyecto, tenemos que especificar mediante un asistente la base de datos sobre la que queremos definir nuestro modelo conceptual. Se trata, por tanto, de un diseño El esquema primero (Schema First). En Visual Studio 2010 podremos definir inicialmente nuestro modelo conceptual, con las correspondientes entidades, sus jerarquías de herencia y sus relaciones, para luego lanzar desde el menú contextual del diseñador un asistente que o bien creará bien ficheros independientes con las sentencias DDL (Data Definition Language) con la sintaxis correspondiente al repositorio de datos elegido, o bien desplegará directamente el correspondiente esquema al servidor de base de datos elegido usando esas mismas sentencias DDL. Por defecto, al generar las sentencias DDL se usa una solución Tabla-por-Tipo (TPT), es decir, se crea una tabla por cada tipo y subtipo. Por ejemplo, para el modelo de la figura 2, se generará el esquema que se muestra en la figura 3.


<< dnm.entityframework

El futuro de EF Muchas son también las mejoras y nuevas capacidades que se incluirán en la próxima versión de las librerías que componen EF. Hemos resumido algunas de las más destacadas a continuación; podrá encontrar más información sobre ellas en la entrevista a Danny Simmons y Diego Vega, destacados miembros del equipo de EF, en este mismo ejemplar. Como sabréis, EF implementa un patrón de diseño denominado Carga perezosa (Lazy Loading). Esto significa que cuando realizamos una consulta sobre un conjunto de entidades, por defecto, los Servicios de objetos no se traen las entidades relacionadas (el grafo correspondiente) de la base de datos. La forma de

especificar la expansión de la consulta, es decir, la inclusión de las entidades relacionadas en el conjunto de resultados, es mediante la utilización del método Include en la definición de la consulta, o bien mediante una llamada explícita a Load para lanzar la correspondiente consulta a la base de datos para obtener las entidades relacionadas. Por ejemplo, en el listado 1 especificamos a través de Include que deseamos obtener adicionalmente los productos correspondientes a las categorías seleccionadas por la consulta; por otro lado, en el listado 2 la carga de los productos la hacemos bajo demanda mediante una llamada a Load.

var contexto = new EntidadesNorthwind(); var categorias = from c in contexto.Categorias. Include(“Productos”) orderby c.Nombre select c; Listado 1. Carga perezosa mediante Include

var contexto = new EntidadesNorthwind(); var categorias = from c in contexto.Categorias orderby c.Nombre select c; categorias.Productos.Load();

Listado 2. Carga perezosa con Load

Como puede ver, en ambos casos la carga de las entidades relacionadas tiene que ser explícita. Si quisiéramos abstraernos de esta necesidad y no cargar el código con llamadas a IsLoaded/Load para comprobar si las relaciones están cargadas y si no lo están hacerlo, podríamos implementar una carga perezosa transparente o implícita, similar a la que ofrece LINQ to SQL. Existen varias estrategias para hacerlo, y una buena forma de revisar las implicaciones y posibilidades de cada una de ellas es acudir al blog de Jaroslaw Kowalski [5]. Pues bien, en la próxima versión de EF podemos contar con ello, y mediante una opción del contexto de trabajo podremos especificar si queremos una carga perezosa implícita. Otra de las mejoras que incluirá la próxima versión será el soporte de objetos POCO (Plain Old CLR Objects). Es decir, las clases correspondientes a las entidades del modelo no tendrán por qué derivar de EntityObject, como ocurre actualmente, de forma que pueda usarse el mismo modelo conceptual de

<<dotNetManía

Es de señalar que la generación de las sentencias DDL se implementa mediante un flujo de trabajo de Workflow Foundation expresado en XAML, por lo que puede sustituirse fácilmente por uno propio, total o parcialmente, por ejemplo, para hacer uso de un esquema Tabla-por-Jerarquía (TPH) en lugar de TPT. Este hecho, como muchas de las nuevas posibilidades en relación con la experiencia de diseño, viene a proporcionarnos una gran capacidad para meternos dentro de los entresijos de la tecnología para permitirnos modificarla y adaptarla a nuestras necesidades. Un paso más allá de la filosofía El modelo primero sería El código primero (Code First). Es decir, que partiendo de clases definidas en .NET podamos generar el correspondiente modelo conceptual de EF. El grupo de producto ha presentado un prototipo con esta capacidad y está estudiando diversas formas de implementarla, aunque por ahora no es posible asegurar que esta característica formará parte de la próxima versión de Visual Studio. Otra mejora reseñable dentro de las herramientas de diseño de EF para la próxima versión lo constituye el soporte para los tipos complejos. Es decir, con Visual Studio 2010 se podrán crear, editar y borrar tipos complejos en el navegador de modelos y usarlos en propiedades de entidades, o como tipo de retorno de procedimientos almacenados. Por otro lado, el mapeo de importación de funciones permitirá especificar cómo se mapean los parámetros de retorno de los procedimientos almacenados a las correspondientes propiedades de las entidades o tipos complejos; en la primera versión, este mapeo era implícito y los nombres tenían que casar. Para terminar con el conjunto de novedades dentro del apartado de herramientas, podemos destacar un excelente soporte para la búsqueda de información dentro de los modelos EDM, incluyendo el resaltado de los elementos visuales.

23


<< dnm.entityframework

una forma independiente del Marco de trabajo usado en el mapeo relacional. Con respecto al soporte del modelo N-capas, la próxima versión de EF ofrecerá varias vías para facilitar el desarrollo de este tipo de aplicaciones, incluyendo un modelo basado en la auto-gestión de los cambios por parte de las entidades (self-tracking entities), de forma que éstas, al serializarse, mantengan la información de estado, y podamos, por tanto, implementar fácilmente modelos de concurrencia optimista en el escenario desconectado. Por otro lado, para mejorar la experiencia de uso de LINQ to Entities, y poder usar en las consultas las funciones canónicas de Entity SQL (matemáticas, de cadenas, de fechas, etc.), se va a permitir la posibilidad de definir métodos que se mapeen a funciones definidas o declaradas en el nivel conceptual (EDM) o en el espacio de almacenamiento (SQL Server, etc.), de forma que a través de estos métodos podamos hacer uso de la función correspondiente dentro de una consulta de LINQ to Entities. Un ejemplo de esta posibilidad se refleja en el listado 3, donde inicialmente mapeamos la función canónica DiffYears, y luego la usamos dentro de una consulta.

Para finalizar, y no menos importante que el resto de novedades, los amantes de TDD (Test Driven Design) encontrarán un gran número de ventajas que les permitirán testear fácilmente las capas de persistencia creadas con EF, no solamente gracias a la aparición del soporte de POCO, sino por el hecho de que la mayoría de API están basadas en interfaces, y por lo tanto son fáciles de simular mediantes los distintos frameworks de mocking que tenemos a nuestra disposición.

Conclusiones Como hemos podido comprobar, el futuro de EF nos depara grandes novedades y mejoras, que harán la experiencia de trabajo con él mucho más productiva y flexible. La próxima versión nos permitirá adaptar mucho fácilmente el comportamiento del marco de trabajo a nuestras necesidades y aumentar en gran medida la productividad del desarrollo, al mismo tiempo que simplificará el mantenimiento de las soluciones basadas en el marco de entidades.

public static class FuncionesEntidades { [EdmFunction(“EDM”, “DiffYears”)] public static Int32? DiffYears(DateTime? arg1, DateTime? arg2) { throw EntityUtil.NotSupported( System.Data.Entity.Strings.ELinq_EdmFunctionDirectCall); } } var consulta = from p in context.Productos where FuncionesEntidades.DiffYears(DateTime.Today, p.FechaCreacion) < 5 select p; Listado 3. Mapeo de funciones del modelo conceptual y uso en LINQ to Entities

Bibliografía [ 1]

Zorrilla, U., Hernández, O., “El Marco de entidades de ADO.NET 3.5” (I-VII), en dotNetManía nº 44-50,

<<dotNetManía

enero-julio de 2008.

24

[ 2] [ 3] [ 4]

http://blogs.msdn.com/efdesign (Blog de diseño de EF)

[ 5]

http://blogs.msdn.com/jkowalski (post sobre EF Lazy Loading)

[ 6]

http://www.olegsych.com/2007/12/text-template-transformation-toolkit (post sobre T4)

http://blogs.msdn.com/adonet (Blog del equipo de ADO.NET) http://blogs.msdn.com/dsimmons (Blog de Danny Simmons)


entity framework

Luis Miguel Blanco

Manipulación de datos en Silverlight

mediante ADO.NET Data Services (I) La evolución en el desarrollo de aplicaciones Web hacia modelos en los que la parte cliente (AJAX, Silverlight) está dotada de una mayor inteligencia y programabilidad está propiciando que la arquitectura de estas aplicaciones se base, cada vez más, en servicios, fundamentalmente en lo relativo a las operaciones de acceso y manipulación de las fuentes de datos utilizadas por la aplicación.

Un claro exponente de este enfoque lo constituye la utilización de ADO.NET Data Services (proyecto inicialmente conocido con el nombre clave Astoria), que a lo largo de las sucesivas entregas de esta serie abordaremos como mecanismo para la manipulación de datos dentro del contexto de aplicaciones Silverlight. En esta primera entrega realizaremos una descripción general de ADO.NET Data Services, y desarrollaremos un ejemplo de creación de un modelo y servicio de datos, sobre el que posteriormente efectuaremos pruebas de acceso y consultas. Si bien el título del artículo indica que utilizaremos Silverlight, por cuestiones de espacio no lo haremos en esta primera parte, reservando los ejemplos de acceso al servicio desde la interfaz de usuario para las siguientes entregas. Luis Miguel Blanco es redactor de dotNetManía y consultor en Alhambra-Eidos. Ha escrito varios libros y decenas de artículos sobre la plataforma .NET. Consulta su blog: http://geeks.ms/blogs/ lmblanco.

ADO.NET Data Services a grandes rasgos Según se explica en [1], podemos definir ADO.NET Data Services como una tecnología basada en la combinación de una serie de librerías y patrones, cuyo principal objetivo radica en posibilitar la cre-

ación y consumo de servicios orientados a datos que se integren de una forma fácil y natural en aplicaciones ejecutadas dentro del entorno Web. Los servicios creados con ADO.NET Data Services permiten la obtención, filtrado, ordenación y demás operaciones habituales sobre los datos. Para lograrlo, se utilizan identificadores URI, que mediante los verbos de HTTP: GET, PUT, POST y DELETE, permiten interactuar con los datos, los cuales se representan como una colección de recursos de tipo REST que se transmiten utilizando formatos como Atom (Atom Publishing Protocol) o JSON (JavaScript Object Notation). Adicionalmente, para organizar y representar conceptualmente el conjunto de entidades y relaciones (asociaciones) que componen un servicio de datos podemos utilizar EDM (Entity Data Model) como herramienta de modelado. A continuación, una vez realizada la introducción teórica a esta tecnología, pasaremos a la parte práctica, en la cual describiremos las principales acciones que necesitaremos implementar para crear un servicio de tipo ADO.NET Data Services, cuyos datos puedan ser consumidos en un futuro por una aplicación cliente desarrollada en Silverlight.


<< dnm.entityframework

Definiendo el modelo de entidades

Figura 1. Cadena de conexión del modelo de datos.

Para organizar y representar conceptualmente el conjunto de entidades y relaciones que componen un servicio de datos, podemos utilizar Entity Data Model (EDM)

entidades de nuestro modelo, que en nuestro caso serán las tablas Customers, Orders, Products, Shippers y Suppliers. Pulsando el botón “Finish”, el asistente generará el modelo a partir de los datos suministrados, ofreciéndonos el diseñador EDM con la representación conceptual en forma de entidades de las tablas seleccionadas. En el caso de que entre las tablas agregadas al modelo existan relaciones, éstas serán representadas como asociaciones dentro del diseñador.

Al igual que ocurre con otros diseñadores, el resultado del diseño que realicemos sobre el EDM se reflejará en un archivo de código, que contiene una clase que representa al propio modelo o contexto de entidades, cuyo nombre (en nuestro caso NorthwindEntities) se compone del nombre de la base de datos más el sufijo Entities. Por otro lado, se crearán tantas clases como entidades hayamos definido en el modelo. Este conjunto de clases será utilizado por el servicio de datos en las operaciones de mapeo y transmisión de datos entre el cliente y el servidor. Es importante destacar que el modelo obtenido no es algo rígido ni inmutable, sino que podemos editar las entidades, añadir nuevas entidades, etc.

Creación del servicio de datos Una vez creado el modelo de entidades, el siguiente paso consiste en crear el servicio de datos, para lo cual volveremos al explorador de soluciones, y haciendo de nuevo clic derecho en el proyecto Web, seleccionaremos la

<<dotNetManía

Es posible crear un servicio de datos de ADO.NET a partir de cualquier origen de datos que implemente la interfaz IQueryable<T> y, opcionalmente, la interfaz IUpdatable, ya sea el origen de datos relacional o no [2]. En nuestro caso emplearemos una fuente de datos relacional, como es la base de datos de ejemplo Northwind de SQL Server. Debido a la naturaleza relacional de esta fuente de datos, es preciso definir un modelo de entidades, que utilizaremos desde el servicio de datos que crearemos posteriormente. En primer lugar, iniciaremos Visual Studio 2008 y crearemos un nuevo proyecto de tipo Silverlight, al que daremos el nombre ServicioDatosConsultaSL. Todos los ejemplos expuestos en el presente artículo se han desarrollado con Visual Studio 2008 y .NET Framework 3.5 Service Pack 1, pudiendo ser descargados desde el sitio Web de la revista, http://www.dotnetmania.com. A continuación, nos situaremos en el Explorador de Soluciones, haremos clic derecho sobre el proyecto Web de esta solución y seleccionaremos la opción “Add” | “New Item”, que abrirá el correspondiente cuadro de diálogo, dentro del cual haremos clic en el elemento ADO.NET Entity Data Model para crear un nuevo modelo de entidades, que grabaremos en un archivo con el nombre mdlNorthwind.edmx. Seguidamente se iniciará el asistente para la creación del modelo de entidades, en el que, como primer paso, indicaremos que nuestro modelo se generará a partir de una base de datos, seleccionando el icono “Generate from database”. En el siguiente paso, que vemos en la figura 1, proporcionaremos la información de conexión a la base de datos, obteniendo como resultado la cadena de conexión que utilizará el servicio para acceder a ella, así como el nombre con el que dicha conexión se almacenará en el archivo Web.config. En el paso final de este asistente, seleccionaremos aquellos elementos de la base de datos que conformarán las

27


<< dnm.entityframework

opción “Add” | “New Item”, eligiendo esta vez el icoSi nos encontramos en Visual Studio 2008, desno “ADO.NET Data Service”, al que daremos el de el Explorador de Soluciones haremos clic derenombre wdsNorthwind.svc. cho en el servicio, seleccionando la opción “Set As Después de aceptar este cuadro de diálogo, Start Page”, con lo que al ejecutar el proyecto desnuestro servicio de datos será creado y Visual Stude el entorno de desarrollo, la ruta que mostrará el dio 2008 abrirá un editor con el código fuente del navegador (debido a que estamos utilizando el sermismo, donde tendremos que añadir código adividor Web de desarrollo) será similar a la siguiente: cional para completar su configuración. http://localhost:55721/wdsNorthwind.svc Por una parte, podemos observar que la clase correspondiente al servicio hereda del tipo genérico DataService<T>, y deberemos sustituir el parámetro de tipo (en cuyo lugar aparece un comentario con el texto “/*TODO: put your data source class name here*/”) por el nombre de la clase que representa al modelo de entidades que recientemente acabamos de crear: NorthwindEntities. Por otro lado, en el método InitializeService utilizaremos el parámetro config, de tipo IDataServiceConfiguration, para establecer las reglas de acceso al servicio llamando a su método SetEntitySetA ccessRule; al que pasaremos como primer parámetro el nombre de las entidades a las que permitiremos acceso (el asterisco indica que se permite el acceso a Figura 2. Listado de entidades del servicio en formato Atom. todas las entidades), mientras que en el segundo parámetro indicaremos el tipo de permiso requerido, que para este ejemplo será En el caso de que ya tengamos alojado el servisin restricciones. Todo ello lo vemos en el listado cio en un directorio virtual mediante IIS, la ruta 1. tendrá el formato habitual, pero apuntando, como es lógico, al servicio: public class wdsNorthwind : DataService<NorthwindEntities> { // This method is called only once to initialize // service-wide policies. public static void InitializeService( IDataServiceConfiguration config) { config.SetEntitySetA ccessRule(“*”,EntitySetRights.A ll); } }

http://localhost/ServicioDatosConsultaSL/ wdsNorthwind.svc/

En ambos casos, el navegador mostrará, como resultado de la llamada al servicio, un listado con la representación de las entidades que lo componen en formato Atom (el formato predeterminado de salida empleado por ADO.NET Data Services), como vemos en la figura 2.

Listado 1. Inicialización del servicio de datos.

<<dotNetManía

Verificando el funcionamiento del servicio de datos

28

Tras finalizar la creación del servicio, el siguiente paso lógico consistirá en comprobar su funcionamiento, y el modo más inmediato de realizar estas pruebas pasa por escribir la ruta del servicio de datos en nuestro navegador Web.

En el caso de que entre las tablas agregadas al modelo existan relaciones, éstas serán representadas como asociaciones dentro del diseñador


<< dnm.entityframework

Acceso al contenido de las entidades del servicio Pero como es natural, además de haber conseguido llegar a la puerta de entrada de nuestro servicio de datos, lo lógico es que queramos acceder a su interior, para así obtener la información contenida en sus entidades. Esto será algo que conseguiremos mediante la combinación de un conjunto de parámetros, operadores y funciones, que pasados en la cadena de consulta (query string) de la ruta de acceso al servicio, nos permitirán moldear los datos resultantes de acuerdo a nuestras necesidades. El primer ejemplo en este sentido consistirá en obtener el contenido al completo de una de las entidades del servicio, para lo que partiremos de cualquiera de las rutas expuestas en el apartado anterior, añadiéndole el nombre de la entidad (Suppliers en este caso) de la siguiente manera: http://localhost/ServicioDatosConsultaSL/ wdsNorthwind.svc/Suppliers

La respuesta obtenida en el navegador después de ejecutar esta llamada al servicio, parte de la cual

Figura 3. Listado de los elementos contenidos en una entidad.


<< dnm.entityframework

La clase correspondiente al servicio hereda del tipo genérico DataService<T>

vemos en la figura 3, muestra cómo cada uno de los elementos <entry> representa un registro de la tabla Suppliers, conteniendo todo el detalle relativo a ese elemento en particular: identificador único de acceso, propiedades, etc. Antes de proseguir, debemos hacer un inciso acerca de la visualización en el navegador del contenido de las entidades, ya que en el caso de utilizar Internet Explorer, es probable que la salida no se muestre en la forma que hemos indicado. Para poder visualizar correctamente el resultado, debemos seleccionar en el navegador la opción de menú “Herramientas” | “Opciones de Internet”; hacer clic en la pestaña “Contenido”, y dentro del apartado “Fuentes”, pulsar el botón “Configuración”, desmarcando a continuación la casilla “Activar la vista de lectura de fuentes”. Supongamos ahora que solamente queremos recuperar un único registro de la entidad. La forma de conseguirlo consiste en adjuntar al nombre de la entidad, encerrado entre paréntesis, el valor de la clave primaria correspondiente al registro; en este caso, alguno de los valores del campo SupplierID, la clave primaria de la tabla/entidad: http://localhost/ServicioDatosConsultaSL/ wdsNorthwind.svc/Suppliers(7)

Si observamos la entidad Suppliers en nuestro modelo EDM, nos percataremos de que existe una asociación entre dicha entidad y Products, a través de la

propiedad SupplierID de ésta última. Esto significa que a partir de un registro de Suppliers podremos obtener también los registros relacionados con él de la entidad Products. El modo de expresar esto en la llamada al servicio pasa por utilizar el parámetro expand, pasándole como valor la entidad asociada de la que queremos obtener los registros relacionados: http://localhost/ServicioDatosConsultaSL/wdsNorthwind.svc/Suppliers(4)?$expand=Products

Otra variante en la selección de los datos la constituye el parámetro filter, que combinado con alguno de los operadores lógicos eq (equal), ne (not equal), gt (greater than), etc., nos permite aplicar un filtro basado en una condición, como vemos en el siguiente ejemplo: http://localhost/ServicioDatosConsultaSL/wdsNorthwind.svc/Suppliers?$filter=Country eq 'Germany'

Y finalizamos esta serie de ejemplos con una petición a nuestro servicio de datos que combina un filtro con los operadores lógicos ge (greater than or equal), and ('y' lógico), le (less than or equal), y finalmente el parámetro orderby, mediante el cual ordenamos el resultado en base a una de las propiedades de la entidad: http://localhost/ServicioDatosConsultaSL/ wdsNorthwind.svc/Suppliers?$filter= SupplierID ge 10 and SupplierID le 20&$orderby= CompanyName

Conclusión Una presentación en profundidad de todas y cada una de las características que podemos emplear en la URL a la hora de consultar un servicio de datos excedería con creces el ámbito de este artículo, por lo que recomendamos al lector la consulta de [3], donde encontrará todos estos aspectos tratados aquí con un mayor grado de amplitud. En la segunda parte de esta serie abordaremos el acceso al servicio desde Silverlight, en aquellos aspectos relacionados con las consultas y presentación de resultados en la interfaz de usuario.

Bibliografía

<<dotNetManía

[ 1]

30

[ 2]

Overview: ADO.NET Data Services. http://msdn.microsoft.com/en-us/library/cc956153.aspx. Data Model and Data Service Implementations (ADO.NET Data Services/Silverlight). http://msdn.microsoft.com/en-us/library/cc838239(VS.95).aspx.

[ 3]

Using Microsoft ADO.NET Data Services. http://msdn.microsoft.com/en-us/library/cc907912.aspx.


Unai Zorrilla, Octavio Hernández

entity framework

Consulta de modelos conceptuales

con Entity SQL (III) Los métodos de construcción de consultas En entregas anteriores de esta serie [1], hemos venido presentando los fundamentos de Entity SQL (eSQL), el lenguaje de consulta de modelos conceptuales incorporado al ADO.NET Entity Framework (en adelante EF), así como las diferentes API que EF pone a nuestra disposición para la ejecución de las consultas. Este mes, en consideración a la naturaleza de este especial sobre EF, hemos preferido apartarnos algo del tema central de la serie y dedicar la columna a los métodos de construcción de consultas de los Servicios de objetos de EF, un tema que se tocó muy ligeramente en la primera entrega y que puede ser muy útil a la hora de implementar consultas parametrizadas y dinámicas sobre modelos conceptuales. Unai Zorrilla es Development Team Leader de Plain Concepts. MVP desde 2004, colabora activamente con Microsoft en eventos de arquitectura y desarrollo, así como en giras de productos. Autor de los libros “Modelando procesos de negocio con Workflow Foundation” y “ADO.NET Entity Framework: Aplicaciones y servicios centrados en datos”. Octavio Hernández es MVP de C# desde 2004, MCSD y MCT. Autor de los libros “C# 3.0 y LINQ" y "ADO.NET Entity Framework: Aplicaciones y servicios centrados en datos" (con Unai Zorrilla y Eduardo Quintás).

Sin lugar a dudas, el principal problema que tenemos a la hora de leer datos de nuestras consultas utilizando Entity Client tiene que ver con la materialización (generación de objetos fuertemente tipados a partir) de los resultados. Como hemos visto en entregas anteriores, el proceso de lectura de las consultas con Entity Client requiere del análisis del tipo de metadatos con el que nos encontramos en cada momento hasta llegar a los tipos primitivos o complejos con los que construir nuestras entidades de transporte de datos. Este proceso es una de las principales fuentes de merma de la productividad, puesto que suele requerir un gran esfuerzo de codificación por parte de los programadores. Consciente de esta limitación, y por otros diversos motivos, el equipo de trabajo de EF pone a nuestra disposición los Servicios de objetos (Object Services), gracias a los cuales se simplifica sobremanera la materialización de los resultados y las consultas sobre los modelos conceptuales de EDM. A lo largo de este artículo veremos cómo utilizar los métodos de construcción de consultas que forman parte de los Servicios de objetos.

Tal y como es costumbre en nuestros artículos, le proponemos el modelo de entidades sobre el que basaremos nuestros ejemplos, que se muestra en la figura 1.

Estableciendo las bases Para empezar, partiremos de un ejemplo sencillo con el que mostrar la primera característica que nos ofrecen los Servicios de objetos: la materialización automática de los resultados de las consultas. Le recomendamos que compare el código utilizado aquí (listado 1), con el de la misma lectura utilizando Entity Client en ediciones anteriores. Observe cómo, automáticamente, los resultados obtenidos de nuestra consulta en eSQL han sido materializados en función de la especificidad de nuestro tipo genérico. La variable dedicada a recibir el resultado de la llamada al método ObjectQuery<T>.Execute podría ser eliminada de una forma sencilla si se enumera directamente el objeto de consulta, el cual hará por nosotros esta llamada (listado 2).


<< dnm.entityframework

NOTA

[ ] Para los casos en los que esté presente la herencia, se podría utilizar cualquiera de los operadores que EF nos provee para ello (de los que hablaremos en nuestra próxima entrega), como son los operadores OFTYPE, TREA T e IS OF.

using (FUTBOL2006Entities dbContext = new FUTBOL2006Entities()) { ObjectQuery<Futbolista> futbolistas = new ObjectQuery<Futbolista>( “SELECT VA LUE f FROM FUTBOL2006Entities.Futbolista as f”, dbContext); ObjectResult<Futbolista> result = futbolistas.Execute(MergeOption.NoTracking); foreach (Futbolista item in result) { Console.WriteLine(“Nombre :{0}”, item.Nombre); } }

Listado 1. Ejecución de consulta mediante los Servicios de objetos

using (FUTBOL2006Entities dbContext = new FUTBOL2006Entities()) { ObjectQuery<Futbolista> futbolistas = new ObjectQuery<Futbolista>( “SELECT VA LUE f FROM FUTBOL2006Entities.Futbolista as f”, dbContext); foreach (Futbolista item in futbolistas) { Console.WriteLine(“Nombre :{0}”, item.Nombre); } }

Listado 2. Ejecución de consulta mediante los Servicios de objetos (2)

Los métodos de construcción de consultas Por supuesto, estará seguro de acuerdo con nosotros en que en la vida real las consultas resultan mucho más complejas, incluyendo muchas más casuísticas sobre la jerarquía de tipos, ordenaciones, filtros, paginaciones y/o agrupaciones, entre otras muchas cosas. De hecho, la actividad de escribir nuestras consultas entrecomilladas es un error frecuente entre de los desarrolladores, que muchas veces produce dolores de cabeza por la dificultad en la lectura de las mismas. Al ser simples cadenas, el compilador nunca podrá inferir cuál es el trabajo que deseamos que la capa de acceso a datos realice, y por lo tanto, nunca podrá echarnos una mano diciéndonos si hemos cometido un error aquí o allí. Si pudiéramos simplificar las consultas, lograríamos minimizar, que no eliminar, estos problemas, al dividir un trabajo complejo en varias o muchas partes simples. Estas divisiones de nuestras consultas en los objetos ObjectQuery<T> son posibles gracias a los denominados métodos de construcción de consultas (SQL Query Builder Methods) de los Servicios de objetos de EF. En la

<<dotNetManía

Figura 1. Modelo de entidades de ejemplo.

ObjectQuery<Futbolista> futbolistas = new ObjectQuery<Futbolista>( “OFTYPE(FUTBOL2006Entities. Futbolista,DNM.Futbolista)”, dbContext);

33


<< dnm.entityframework

Método de construcción

Expresión en eSQL

Distinct

DISTINCT

Except

EXCEPT

GroupBy Intersect OfType OrderBy Select Skip Top Union UnionA ll WHERE

GROUP BY INTERSECT OFTYPE ORDER BY SELECT SKIP TOP y UNION UNION UNION A LL WHERE

Tabla 1. Métodos de construcción de consultas y sus equivalencias en eSQL.

using (FUTBOL2006Entities dbContext = new FUTBOL2006Entities()) { ObjectQuery<Futbolista> futbolistas = new ObjectQuery<Futbolista>( @”SELECT VA LUE f FROM FUTBOL2006Entities.Futbolista as f WHERE f.Club.Nombre=’REA L MA DRID’ ORDER BY f.Nombre SKIP 0 LIMIT 5”, dbContext); foreach (Futbolista item in futbolistas) { Console.WriteLine(“Nombre :{0}”,item.Nombre); } } Listado 3. Ejecución de consulta mediante los Servicios de objetos (3)

using (FUTBOL2006Entities dbContext = new FUTBOL2006Entities()) { ObjectQuery<Futbolista> futbolistas = new ObjectQuery<Futbolista>(“Futbolista”, dbContext);

tabla 1 se presenta una lista de los métodos de construcción presentes en ObjectQuery<T> y cuáles son sus cláusulas homólogas en eSQL. A lo largo de las siguientes líneas, trataremos de mostrar algunos ejemplos de uso de varios de los métodos de construcción de consultas sobre nuestro modelo conceptual de ejemplo. Un primer ejemplo podría ser la recuperación de todos los futbolistas pertenecientes al Real Madrid (perdone la licencia), ordenados alfabéticamente y paginados de cinco en cinco elementos. El listado 3 muestra una manera básica de implementar la consulta con los Servicios de objetos. A pesar de ser la anterior una sentencia sencilla, puede darse cuenta de cómo hay muchas posibilidades de introducir una errata en el código eSQL incluido. Gracias a los métodos de construcción de consultas, las diferentes cláusulas de la consulta pueden introducirse independientemente, con lo que la susceptibilidad de errores se reduce en buena medida (aunque no se elimina completamente: observe que los parámetros de los métodos de construcción siguen siendo cadenas de caracteres), y además mejora la comprensión de la consulta como un todo. El listado 4 implementa la misma consulta utilizando varios métodos de construcción. Note cómo los distintos métodos de construcción de consultas devuelven a su vez objetos ObjectQuery<T>, con el fin de facilitar el encadenamiento (chaining) de llamadas tan típico de LINQ.

Utilización de parámetros

<<dotNetManía

futbolistas = futbolistas .Where(“it.Club.Nombre=’REA L MA DRID’”)) .Skip(“it.Nombre DESC”, “0”) .Top(“5”); foreach (Futbolista item in futbolistas) { Console.WriteLine(“Nombre :{0}”,item.Nombre); }

34

} Listado 4. Consulta que utiliza métodos de construcción

Al igual que en las sentencias eSQL (que es en el fondo lo que se construye al final de una cadena de ejecución de consulta para ser enviada a Entity Client), pueden utilizarse parámetros en los argumentos de los métodos de construcción de consultas. Por ejemplo, la consulta del listado 4 pudo haberse escrito también como se muestra en el listado 5, utilizando un parámetro para el nombre del equipo.


<< dnm.entityframework

futbolistas = futbolistas .Where(“it.Club.Nombre=@nombre”, new ObjectParameter(“nombre”, “REA L MA DRID”)) .Skip(“it.Nombre DESC”, “0”) .Top(“5”);

que trabajemos; para ello, es suficiente con establecer la propiedad Name del citado tipo, tal y como se muestra en el listado 6.

Conclusión Listado 5. La consulta del listado 4, utilizando un parámetro

El identificador "it" Es probable que le resulte curioso el uso de las expresiones con "it" dentro de nuestras consultas en eSQL. "it" ("eso") hace referencia de manera predeterminada al nombre dado a la entidad que se consulta. Por supuesto, este “alias por defecto” es modificable para cada uno de los objetos ObjectQuery<T> con los

En este artículo hemos presentado los fundamentos de los métodos de construcción de consultas de EF. Sin lugar a dudas, estos métodos nos permiten reducir en buena medida la propensión a errores en la escritura de consultas y nos ofrecen la posibilidad de crear un sistema de consultas parametrizadas y/o dinámicas, con una materialización automática de los resultados. Desde aquí, estimado lector, le sugerimos que investigue y practique el uso de los métodos de construcción de consultas, que sin dudas le darán más de una alegría durante sus desarrollos.

using (FUTBOL2006Entities dbContext = new FUTBOL2006Entities()) { ObjectQuery<Futbolista> futbolistas = new ObjectQuery<Futbolista>(“Futbolista”, dbContext); // Modificamos el alias por defecto “it” por “jugador” futbolistas.Name = “jugador”; futbolistas = futbolistas. Where(“jugador.Club.Nombre=@nombre”, new ObjectParameter(“nombre”, “REA L MA DRID”)); foreach (Futbolista item in futbolistas) { // TODO: procesar futbolista } } Listado 6. Asignando nombres a las entidades

[ 1]

Zorrilla, U., Hernández, O., “Consulta de modelos conceptuales con Entity SQL” (I y II), en dotNetManía nº 56-57, enero-febrero de 2009.

[ 2]

Zorrilla, U., Hernández, O., Quintás E., “ADO.NET Entity Framework. Aplicaciones y servicios centrados en datos”, Krasis Press, 2008. En particular, el Apéndice B ofrece una referencia de Entity SQL.

[ 3]

Zorrilla, U., Hernández, O., “El Marco de Entidades de ADO.NET 3.5” (I-VII), en dotNetManía nº 44-50, enero-julio de 2008.

[ 4]

Documentación de Entity SQL en MSDN, en http://msdn.microsoft.com/en-us/library/bb399560.aspx.

<<dotNetManía

Bibliografía

35


Guillermo de la Torre Miguel Katrib

entity framework

Implementación de un Membership Provider basada en

ADO.NET Entity Framework

En este artículo se analiza SqlMembershipProvider, el proveedor de membresía (pertenencia) de ASP.NET para SQL Server, y se propone una implementación funcionalmente similar a la de este proveedor, pero basada en ADO.NET Entity Framework.

Guillermo de la Torre es estudiante de la Maestría en Ciencia de la Computación de la Universidad de La Habana y colaborador del grupo WEBOO. Trabaja como desarrollador de software en el Centro Nacional de Neurociencias. Miguel Katrib es doctor y profesor jefe de programación del departamento de Ciencia de la Computación de la Universidad de La Habana. Miguel es líder del grupo WEBOO, dedicado a la orientación a objetos y la programación en la Web. Es entusiasta de .NET y redactor de dotNetManía.

Se ha hecho común en la arquitectura de software el diseño basado en proveedores. La infraestructura de ASP.NET ofrece servicios de gestión de los usuarios de un sitio Web, y para ello la comunicación con la fuente de almacenamiento descansa en lo que se conoce como proveedor de membresía o pertenencia (Membership Provider), un heredero de la clase System.Web.Security.MembershipProvider. ASP.NET 2.0 incluye de manera predeterminada dos implementaciones de proveedores de membresía: • SqlMembershipProvider, que mantiene los datos de membresía en una base de datos Microsoft SQL Server o Microsoft SQL Server Express. • A ctiveDirectoryMembershipProvider, que recupera los datos de membresía de Microsoft Active Directory.

componen, sino que se delega en procedimientos almacenados [1]. Esta concepción permite que el funcionamiento para esquemas lógicos diferentes pueda resolverse modificando solamente procedimientos almacenados. Sin embargo, el esfuerzo necesario para adaptarse a un esquema lógico distinto puede ser tedioso, ya que son más de 16 los procedimientos almacenados que dan soporte al acceso a datos relacionado con la gestión de la membresía. Por otro lado, el desarrollador de la aplicación Web que usa la API de membresía no tiene necesariamente que estar familiarizado con T-SQL. Por lo tanto, sería deseable que el proveedor de membresía no dependiera del esquema lógico de base de datos ni del sistema de gestión de base de datos.

En este artículo se analiza SqlMembershipProvider y se propone una implementación funcio-

Hacia un mejor enfoque

nalmente similar a la de este proveedor, pero basada en ADO.NET Entity Framework (en adelante EF). SqlMembershipProvider almacena los datos de membresía usando un esquema pre-establecido de base de datos SQL. El acceso a los datos no se realiza directamente sobre las tablas que la

EF se ajusta a las exigencias impuestas por un escenario como éste. Su modelo de datos de entidades (Entity Data Model, EDM) nos ofrece un alto nivel de abstracción del almacén de datos. La esencia de este nuevo marco de trabajo es proveer un contexto donde la atención se centre en entes conceptuales llamados entidades y las distintas relaciones entre


<< dnm.entityframework

ellos; el esquema lógico de los datos queda en segundo plano, salvo a la hora de especificar cómo asociar cada entidad hacia y desde la fuente de datos. Lo que hay que hacer ahora es trasladar el conocimiento del proveedor de membresía del esquema de los datos del nivel lógico al nivel conceptual. La estructura pre-establecida esta vez se impone como un EDM, en adelante referido como ASP.NET Provider Data Model o simplemente Provider Data Model, y cada almacén de datos deberá especificar su debida correspondencia con esta especie de base de datos conceptual. Gracias a ello, se podrá considerar como medio de almacenamiento posible para el servicio de membresía toda fuente de datos para la que sea posible: • Asociarla a las entidades correspondientes • Disponer del soporte de EF requerido para la gestión de los datos. El soporte de EF necesario para cada uno de los sistemas de gestión de base de datos del mercado es implementado generalmente por las mismas compañías que los sustentan, o por terceros interesados comercialmente.

soft SQL Server Express a varios exponentes del modelo de proveedores de ASP.NET, entre ellos el de membresía. Este esquema lógico se puede obtener con la herramienta aspnet_regsql; para ello, ejecute esta utilidad desde Visual Studio 2008 Command Prompt y siga los pasos del asistente que aparecerá. Nuestro modelo de datos, al menos para esta etapa, obedecerá lo más Figura 1. Creando el ASP.NET Provider Data Model fielmente posible al esquema lógico original con respecto a tablas físicas (no vistas) y procedimientos almacenamiembros. No obstante, nuestra intendos (figura 1). ción no es definir un modelo de datos Una alternativa pudiera basarse en ideal, sino mostrar los beneficios de que aspnet_Membership herede de asptrasladar el conocimiento acerca del net_Users, pero habría entonces que almacén de datos de membresía de un enfocarse en decisiones como la de qué nivel lógico a un nivel conceptual. La hacer con la relación de aspnet_Memfigura 2 muestra el modelo, generado bership con aspnet_A pplications, muy automáticamente a partir de la base de pertinente en el esquema lógico por disdatos original, sobre el cual operará minuir la necesidad de realizar encuennuestro EdmMembershipProvider, un protros (joins) y optimizar las consultas de veedor de membresía basado en EF.

El esquema de base de datos sobre el que opera SqlMembershipProvider fue concebido no solo con la idea del servicio de membresía en mente, sino también pensando en otros servicios disponibles hoy, como el de la gestión de estado de sesión, y con la posibilidad de que se desee adicionar nuevos servicios en el futuro. Este esquema contiene tablas que son específicas de algún proveedor y otras que son de propósito general [2]. Por simplicidad, el esquema lógico de base de datos sobre el cual trabajaremos en este artículo es el que fue propuesto por Microsoft para ofrecer soporte de almacenamiento en una base de datos Microsoft SQL Server o Micro-

Figura 2. ASP.NET Provider Data Model

<<dotNetManía

ASP.NET Provider Data Model

37


<< dnm.entityframework

EdmMembershipProvider El dominio de fuentes de datos sobre las cuales pudiera operar EdmMembershipProvider es amplio y puede ser medido por la capacidad de mapeo de EDM. No obstante, una solución que obvie completamente los procedimientos o funciones del almacén no es lo mejor, puesto que éstos en ocasiones pudieran ser la decisión más acertada. Imagine escenarios donde evitar viajes de ida y vuelta de datos (roundtrips), desatar acciones complejas en el servidor ante condiciones aleatorias o una alta explotación de la potencia del lenguaje de consulta nativo sean requerimientos prioritarios. La gran diferencia con el enfoque de SqlMembershipProvider es el hecho de que no será la estrategia primaria, sino una alternativa para cuando las necesidades rebasen el alcance del EDM. Tendremos entonces dos contextos totalmente distintos de comportamiento operacional:

Operación CreateUser

• Acceso a datos, caracterizado por delegar la ejecución en llamadas a procedimientos almacenados. • Esquema de datos, que se basa en consultar el modelo. Un modo de comportamiento de una operación se especifica según uno de los dos correspondientes valores del tipo enumerado ProgrammabilityMode: DataA ccess para acceso a datos y DataSchema para esquema de datos. Una clase que herede de System. Web.Security.MembershipProvider debe implementar los métodos de ésta para garantizar una adecuada interacción con el servicio de membresía. Cada una de estas operaciones, según EdmMembershipProvider, sería ejecutada en solo uno de los modos posibles de comportamiento funcional. La tabla 1 muestra las operaciones básicas de todo proveedor de membresía y los correspondientes atributos (de valores DataA ccess o DataSchema) especificables por operación para manipular su modo de comportamiento.

Atributo createUserMode

<<dotNetManía

ChangePasswordQuestionA ndA nswer changePasswordQuestionA ndA nswerMode

38

GetPassword

getPasswordMode

ChangePassword

changePasswordMode

ResetPassword

resetPasswordMode

UpdateUser

updateUserMode

ValidateUser

validateUserMode

UnlockUser

unlockUserMode

GetUser (sobrecarga por identificador)

getUserByUserIdMode

GetUser (sobrecarga por nombre)

getUserByNameMode

GetUserNameByEmail

getUserNameByEmailMode

DeleteUser

deleteUserMode

GetA llUsers

getA llUsersMode

GetNumberOfUsersOnline

getNumberOfUsersOnlineMode

FindUsersByName

findUsersByNameMode

FindUsersByEmail

findUsersByEmailMode

Tabla 1. Operaciones de un proveedor de membresía y sus respectivos atributos de especificación de modo de programabilidad en EdmMembershipProvider

La implementación interna de cada uno de estos métodos obedecería un patrón de la forma “si mi correspondiente modo de programabilidad es igual a DataA ccess, invoco el procedimiento almacenado asociado; si no, consulto el modelo de datos”. Es importante destacar el nivel de granularidad que ofrece este control por operaciones, permitiendo un modo mixto de comportamiento, que posibilita que algunas operaciones se ejecuten mediante llamadas a procedimientos almacenados y otras consultando el modelo. Para evitar tener que hacer una configuración exhaustiva, establezca primero el valor por defecto con el atributo defaultMode y luego declare todos aquellos modos que difieran del valor por defecto. Visto desde la perspectiva de programación, EDM es un almacén de datos más y por tanto debe integrarse a las tecnologías de acceso a datos de .NET. EF ofrece una API para consultar modelos conceptuales siguiendo el patrón de diseño de clientes ADO.NET, que se denomina EntityClient. Leer datos mediante este cliente suele ser mucho más complicado, dado que las columnas no tienen por qué ser siempre valores simples sino que pudieran ser a su vez colecciones de datos; por ejemplo, para contener los resultados de la consulta de una propiedad de navegación. Su consulta se basa en un lenguaje estilo SQL, pero diseñado específicamente para manipular entidades: eSQL. Este escenario de uso es idóneo cuando usted necesita obtener resultados autodescriptivos, pero es trabajoso para situaciones simples. Para facilitar las cosas, EF ofrece una capa superior sobre EntityClient, conocida como Object Services, en la que las consultas también se expresan mediante eSQL, pero los resultados se pueden obtener como objetos. Finalmente, una tercera variante de interacción con un modelo conceptual es LINQ to Entities, un dialecto de LINQ para consultar modelos de entidades. Todo este entorno es provisto por EF; para más información al respecto, revise [5]. Consultar el modelo (modo de programabilidad DataSchema) se refiere a basarse en una de estas tres alternativas, según sea más conveniente.


<< dnm.entityframework

Explicación

membershipProvider

Indica que la fuente de datos incluye soporte para el Membership Provider.

roleProvider

Indica que la fuente de datos incluye soporte para el Role Provider.

siteMapProvider

Indica que la fuente de datos incluye soporte para el Site Map Provider.

sessionStateProvider

Indica que la fuente de datos incluye soporte para el Session State Provider.

profileProvider

Indica que la fuente de datos incluye soporte para el Profile Provider.

webEventProvider

Indica que la fuente de datos incluye soporte para el Web Event Provider.

webPartsPersonalizationProvider Indica que la fuente de datos incluye soporte para el Web Parts Personalization Provider. Tabla 2. Documentación de los atributos de manifiesto

Configuración e inicialización del EdmMembershipProvider De todos los métodos de un proveedor, el primero que se invoca es Initialize , que recopila toda la información de la configuración y prepara la instancia para las llamadas subsiguientes. Es una operación funcional que obedece al patrón de diseño general heredado de ProviderBase, la clase base para el modelo extensible de proveedores en .NET. En este punto es donde se hacen los chequeos de validación. Además de aquellos atributos XML reconocidos por todo proveedor de membresía, como passwordFormat y applicationName, EdmMembershipProvider reconoce: • Los modos de programabilidad por operación, que incluyen los referidos en la tabla 1 y el especial defaultMode. • El manifiesto de los proveedores cuyo soporte tiene instalado la fuente de datos; esto es, tablas, procedimientos y todo elemento del esquema de datos en cuestión (tabla 2). Estos atributos se hacen necesarios por el desconocimiento que se tiene en el modelo de la verdadera naturaleza lógica del almacén.

Los atributos de manifiesto se utilizan debido a la incapacidad por parte del modelo conceptual de conocer el esquema lógico real del almacén de datos. Por ejemplo, cuando se elimine un usuario, debe existir una forma de borrar en consecuencia el perfil del usuario si existiese también soporte para un proveedor de perfiles (ProfileProvider). Vea en el listado 1 una configuración típica de un EdmMembershipProvider.

Procedimientos almacenados en el ASP.NET Provider Data Model En un EDM es posible hacer uso de procedimientos almacenados de dos formas: como entradas de modificaciones para un tipo de entidad determinado (inserción, actualización y eliminación) o como funciones de importación. La primera es parcialmente válida para embeber lógica de cambios en el ASP.NET Provider Data Model, pero solo funcionaría si el modo de programabilidad de las operaciones, que provoquen cambios en la entidad de interés, es DataSchema. La función de importación es el recurso de modelado que más hemos explotado, tratando así a los procedimientos almacenados como “ciudadanos del nivel conceptual”. Al importarse una función, debe especificarse si retornará datos o no, y en caso positivo indicar un tipo de retorno, que puede ser una entidad o un tipo escalar. La generación automática de código dotará entonces de un método equivalente al descendiente de ObjectContext generado. Si el tipo de retorno es una entidad, todo funciona sin problemas. Sin embargo, deben distinguirse tres patrones fundamentales que hay que “retocar”

<membership defaultProvider=“EdmProvider“ userIsOnlineTimeWindow=“20“> <providers> <add name=“EdmProvider“ type=“Providers.EdmMembershipProvider“ connectionStringName=“EntitiesProviderConnection“ enablePasswordRetrieval=“false“ enablePasswordReset=“true“ requiresQuestionA ndA nswer=“true“ passwordFormat=“Hashed“ applicationName=“SecuredA pplication“ defaultMode=“DataSchema“ membershipProvider=“true“/> </providers> </membership> Listado 1. Configuración típica de EdmMembershipProvider

<<dotNetManía

Atributo de manifiesto

39


<< dnm.entityframework

para lograr un modelo de objetos homogéneo: • Procedimiento almacenado que retorna un tipo escalar (ya sea directamente como resultado de consulta o estratégicamente mediante el valor de retorno del procedimiento). • Procedimiento almacenado que retorna un tipo anónimo. • Procedimiento almacenado con parámetros de salida. Cualquiera de estos casos impide la generación automática de un método equivalente en la capa de objetos, por lo que es necesario resolverlos manualmente. En los métodos generados automáticamente que retornan entidades se aprecia un proceder bastante claro: primero crear y configurar por cada parámetro de la función un objeto asociado de tipo ObjectParameter y posteriormente invocar ObjectContext. ExecuteFunction<T> con el conjunto de objetos ObjectParameter previamente configurados, donde T es el tipo de entidad a retornar. Observe la signatura de ExecuteFunction<T> en el listado 2: functionName representa el nombre del procedimiento o función a llamar y parameters los parámetros previamente configurados. Con ObjectResult<T> se puede iterar sobre los resultados. Veamos en lo que sigue cómo lidiar similarmente con procedimientos almacenados que devuelven tipos escalares mediante el valor de retorno del procedimiento o tipos anónimos.

protected ObjectResult<TElement> ExecuteFunction<TElement> ( string functionName, params ObjectParameter[] parameters ) where TElement: IEntityWithChangeTracker Listado 2. Signatura de ObjectContext.ExecuteFunction<T>

invocar el procedimiento mediante EntityClient y efectuar manualmente la lectura del valor de retorno. Para ello hemos desarrollado el método extensor del listado 3. Con este método se puede entonces ejecutar procedimientos que no produz-

public static void ExecuteNonQuery(this ObjectContext ctx, string functionName, out int returnCode, bool checkReturnCode, params EntityParameter[] parameters) { DbCommand cmd = cmd.CommandText cmd.CommandType cmd.Parameters.A

<<dotNetManía 40

ctx.Connection.CreateCommand(); = ctx.DefaultContainerName+“.”+functionName; = System.Data.CommandType.StoredProcedure; ddRange(parameters);

EntityParameter returnValue = new EntityParameter(“ReturnValue”, System.Data.DbType.Int32); returnValue.Direction = System.Data.ParameterDirection.ReturnValue; cmd.Parameters.A dd(returnValue); bool closed = false; if(cmd.Connection.State == System.Data.ConnectionState.Closed) { cmd.Connection.Open(); closed = true; } try { cmd.ExecuteNonQuery(); } finally { if (closed) cmd.Connection.Close(); }

Procedimiento almacenado que “retorna” tipo escalar mediante el valor de retorno Esta característica no está soportada completamente en la versión 1.0 de EF. Se puede importar un procedimiento almacenado que estratégicamente devuelva un tipo escalar en el valor de retorno, pero su equivalente en el modelo de objetos no se generará. Sin embargo, es posible

can resultado o que estratégicamente retornen un valor escalar. Soporta adicionalmente parámetros de salida, obtención del valor de retorno con que finalizó la ejecución –aun cuando no se produzca directamente resultado alguno– e incluso permite optar por el chequeo de

returnCode = (int)returnValue.Value; if (checkReturnCode && (returnCode != 0)) throw new ReturnCodeException(returnCode); } Listado 3. Método extensor ExecuteNonQuery


<< dnm.entityframework

internal int GetNumberOfUsersOnline(string applicationName, int minutesSinceLastInA ctive, DateTime currentTimeUtc) { int returnCode; this.ExecuteNonQuery(“GetNumberOfUsersOnline”, out returnCode, false, ProvidersUtility.CreateInputParam( “A pplicationName”, System.Data.DbType.String, applicationName), ProvidersUtility.CreateInputParam( “MinutesSinceLastInA ctive”, System.Data.DbType.Int32, minutesSinceLastInA ctive), ProvidersUtility.CreateInputParam( “CurrentTimeUtc”, System.Data.DbType.DateTime, currentTimeUtc) );

Nuestro método extensor ExecuteNonQuery invoca el procedimiento almacenado mediante EntityClient y efectúa manualmente la lectura del valor de retorno

return returnCode;

Listado 4. Llamada a procedimiento que retorna un tipo escalar

no sería suficiente, porque habría que reemplazar la llamada a DbCommand.ExecuteNonQuery por DbCommand.ExecuteScalar. El listado 6 ejemplifica una llamada a la función con que se crea un usuario, pero el código de retorno esta vez informa el tipo de error ocurrido si no se pudo efec-

public static EntityParameter CreateInputParam(string paramName, DbType dbType, object objValue) { EntityParameter parameter = new EntityParameter(paramName, dbType); if (objValue == null) { parameter.IsNullable = true; parameter.Value = DBNull.Value; return parameter; } parameter.Value = objValue; return parameter; } Listado 5. Método estático para la creación y configuración de un parámetro

tuar la creación (cero en ausencia de errores). Ambos casos utilizan el método ExecuteNonQuery anterior con semánticas distintas. Por último, el listado 5 muestra el método estático CreateInputParam de la clase ProvidersUtility, útil en estas implementaciones porque modulariza la creación y configuración de un parámetro de entrada.

Procedimiento almacenado que retorna tipo anónimo Un caso un poco más complicado son los procedimientos almacenados que retornan estructuras; el problema es debido a que EDM aún no soporta resultados estructurados que no sean entidades. La solución es entonces modelar entidades ficticias que sean compatibles en número, tipo y nombre con las columnas que devuelve el procedimiento almacenado.

<<dotNetManía

este último para detectar ejecuciones fallidas. El listado 4 muestra una llamada a la función para consultar la cantidad de usuarios conectados, donde el valor de retorno es la cantidad solicitada. Si se tratara propiamente de un procedimiento que retorna un tipo escalar ExecuteNonQuery

41


<< dnm.entityframework

internal void CreateUser(string applicationName, string userName, string password, string passwordSalt, string email, string passwordQuestion, string passwordA nswer, bool isA pproved, DateTime currentTimeUtc, DateTime? createDate, int uniqueEmail, int passwordFormat, ref Guid userId, out int status) { // Parámetro de salida EntityParameter userIdParameter = ProvidersUtility.CreateInputParam( “UserId”, System.Data.DbType.Guid, userId ); userIdParameter.Direction = System.Data.ParameterDirection.Output; EntityParameter[] parameters = new EntityParameter[] { ProvidersUtility.CreateInputParam(“A pplicationName”, System.Data.DbType.String, applicationName), ProvidersUtility.CreateInputParam(“UserName”, System.Data.DbType.String, userName), ProvidersUtility.CreateInputParam(“Password”, System.Data.DbType.String, password), ProvidersUtility.CreateInputParam(“PasswordSalt”, System.Data.DbType.String, passwordSalt), ProvidersUtility.CreateInputParam(“Email”, System.Data.DbType.String, email), ProvidersUtility.CreateInputParam(“PasswordQuestion”, System.Data.DbType.String, passwordQuestion), ProvidersUtility.CreateInputParam(“PasswordA nswer”, System.Data.DbType.String, passwordA nswer), ProvidersUtility.CreateInputParam(“IsA pproved”, System.Data.DbType.Boolean, isA pproved), ProvidersUtility.CreateInputParam(“CurrentTimeUtc”, System.Data.DbType.DateTime, currentTimeUtc), ProvidersUtility.CreateInputParam(“CreateDate”, System.Data.DbType.DateTime, createDate), ProvidersUtility.CreateInputParam(“UniqueEmail”, System.Data.DbType.Int32, uniqueEmail), ProvidersUtility.CreateInputParam(“PasswordFormat”, System.Data.DbType.Int32, passwordFormat), userIdParameter };

<<dotNetManía

this.ExecuteNonQuery(“CreateUser”, out status, false, parameters); userId = (Guid)userIdParameter.Value;

42

} Listado 6. Llamada a procedimiento con parámetro de salida (UserId)

En el listado 7 se muestra un fragmento de código del procedimiento almacenado aspnet_membership_GetUserByName, que retorna los datos del miembro con un nombre específico.

SELECT m.Email, m.PasswordQuestion, m.Comment, m.IsA pproved, m.CreateDate, m.LastLoginDate, u.LastA ctivityDate, m.LastPasswordChangedDate, u.UserId, m.IsLockedOut, m.LastLockoutDate FROM dbo.aspnet_A pplications a, dbo.aspnet_Users u, dbo.aspnet_Membership m WHERE @UserId = u.UserId A ND u.UserId = m.UserId

Listado 7. Ejemplo de sentencia de retorno en aspnet_membership_GetUserByName

Veamos cómo efectivamente enfrentar este caso. Lo primero que se debe hacer es definir el EntityType y el EntitySet en el SSDL (listados 8 y 9, res-

<EntityType Name=“aspnet_trick_GetUserByName“> <Key> <PropertyRef Name=“UserId“/> </Key> <Property Name=“Email“ Type=“nvarchar“ MaxLength=“256“ /> <Property Name=“PasswordQuestion“ Type=“nvarchar“ MaxLength=“256“ /> <Property Name=“Comment“ Type=“ntext“ /> <Property Name=“IsA pproved“ Type=“bit“ Nullable=“false“ /> <Property Name=“CreateDate“ Type=“datetime“ Nullable=“false“ /> <Property Name=“LastLoginDate“ Type=“datetime“ Nullable=“false“ /> <Property Name=“LastA ctivityDate“ Type=“datetime“ Nullable=“false“ /> <Property Name=“LastPasswordChangedDate“ Type=“datetime“ Nullable=“false“ /> <Property Name=“UserId“ Type=“uniqueidentifier“ Nullable=“false“ /> <Property Name=“IsLockedOut“ Type=“bit“ Nullable=“false“ /> <Property Name=“LastLockoutDate“ Type=“datetime“ Nullable=“false“ /> </EntityType> Listado 8. EntityType ficticio (SSDL)


<< dnm.entityframework

Listado 9. EntitySet ficticio (SSDL)

<EntityType Name=“aspnet_trick_GetUserByName“ a:TypeA ccess=“Internal“ xmlns:a=“http://schemas.microsoft.com/ado/2006/04/codegeneration“> <Key> <PropertyRef Name=“UserId“ /> </Key> <Property Name=“Email“ Type=“String“ MaxLength=“256“ Unicode=“true“ FixedLength=“false“ /> <Property Name=“PasswordQuestion“ Type=“String“ MaxLength=“256“ Unicode=“true“ FixedLength=“false“ /> <Property Name=“Comment“ Type=“String“ MaxLength=“Max“ Unicode=“true“ FixedLength=“false“ /> <Property Name=“IsA pproved“ Type=“Boolean“ Nullable=“false“ /> <Property Name=“CreateDate“ Type=“DateTime“ Nullable=“false“ /> <Property Name=“LastLoginDate“ Type=“DateTime“ Nullable=“false“ /> <Property Name=“LastA ctivityDate“ Type=“DateTime“ Nullable=“false“ /> <Property Name=“LastPasswordChangedDate“ Type=“DateTime“ Nullable=“false“ /> <Property Name=“UserId“ Type=“Guid“ Nullable=“false“ /> <Property Name=“IsLockedOut“ Type=“Boolean“ Nullable=“false“ /> <Property Name=“LastLockoutDate“ Type=“DateTime“ Nullable=“false“ /> </EntityType>

Listado 10. EntityType ficticio (CSDL)

<EntitySet Name=“aspnet_trick_GetUsersByName“ EntityType=“ProviderModel.aspnet_trick_GetUserByName“ a:GetterA ccess=“Private“ xmlns:a=“http://schemas.microsoft.com/ado/2006/04/codegeneration“ />

Listado 11. EntitySet ficticio (CSDL)

Para hacer uso de los procedimientos almacenados que retornan tipos anónimos, modelamos entidades ficticias que sean compatibles en número, tipo y nombre con las columnas que devuelve el procedimiento

pectivamente). En este último se hace uso de consultas definitorias ( DefiningQuery) como vía para incluir texto descriptivo. De manera similar, hay que definir la contrapartida en los conceptos. En el nivel conceptual existe la preocupación de que estos falsos tipos no sean expuestos a los clientes de las clases generadas, porque una consulta sobre ellos conllevaría a un error en ejecución puesto que “False Entity Set” no es una consulta válida. Note el uso de modificadores de visibilidad. Definamos el EntityType y el EntitySet en el CSDL (listados 10 y 11, respectivamente). Ahora ya podemos especificar el mapeo entre los tipos: el del aspnet_ trick_GetUserByName del SSDL con el aspnet_trick_GetUserByName del CSDL (listado 12). Luego se debe importar, apoyado en el diseñador visual, la función aspnet_membership_GetUserByName, definiendo como tipo de retorno la entidad aspnet_trick_GetUserByName [4].

<<dotNetManía

<EntitySet Name=“aspnet_trick_GetUsersByName“ EntityType=“ProviderModel.Store.aspnet_trick_GetUserByName“> <DefiningQuery> False Entity Set </DefiningQuery> </EntitySet>

43


<< dnm.entityframework

<EntitySetMapping Name=“aspnet_trick_GetUsersByName“> <EntityTypeMapping TypeName=“IsTypeOf(ProviderModel.aspnet_trick_GetUserByName)“> <MappingFragment StoreEntitySet=“aspnet_trick_GetUsersByName“> <ScalarProperty Name=“LastLockoutDate“ ColumnName=“LastLockoutDate“ /> <ScalarProperty Name=“IsLockedOut“ ColumnName=“IsLockedOut“ /> <ScalarProperty Name=“UserId“ ColumnName=“UserId“ /> <ScalarProperty Name=“LastPasswordChangedDate“ ColumnName=“LastPasswordChangedDate“/> <ScalarProperty Name=“LastA ctivityDate“ ColumnName=“LastA ctivityDate“ /> <ScalarProperty Name=“LastLoginDate“ ColumnName=“LastLoginDate“ /> <ScalarProperty Name=“CreateDate“ ColumnName=“CreateDate“ /> <ScalarProperty Name=“IsA pproved“ ColumnName=“IsA pproved“ /> <ScalarProperty Name=“Comment“ ColumnName=“Comment“ /> <ScalarProperty Name=“PasswordQuestion“ ColumnName=“PasswordQuestion“ /> <ScalarProperty Name=“Email“ ColumnName=“Email“ /> </MappingFragment> </EntityTypeMapping> </EntitySetMapping> Listado 12: Mapeo de aspnet_trick_GetUserByName (SSDL) con aspnet_trick_GetUserByName (CSDL)

Conclusiones En este artículo se han analizado los beneficios de trasladar el modelo de proveedor de membresía de ASP.NET de

un nivel lógico a un nivel conceptual. Se ha presentado una implementación de proveedor basado en EF, EdmMembershipProvider, explicándose los principios de su funcionamiento, la flexi-

Hemos analizado los beneficios de trasladar el modelo de proveedor de membresía de ASP.NET de un nivel lógico a un nivel conceptual

bilidad de su comportamiento operacional y el modelo conceptual sobre el que opera: el ASP.NET Provider Data Model. Posteriormente, se ha discutido sobre cómo dotar a la capa de objetos del modelo con métodos de instancia que invoquen procedimientos almacenados importados como funciones, comenzando con aquellos que retornan tipos escalares, a la vez que permitan parámetros de salida, o que retornen tipos anónimos. En una próxima entrega se espera completar las especificidades de las funciones importadas y repasar diferentes escenarios y casos de estudio.

<<dotNetManía

Bibliografía

44

[ 1]

Microsoft Corporation. Membership providers. http://msdn.microsoft.com/en-us/library/aa478949.aspx.

[ 2]

Microsoft Corporation. Microsoft ASP.NET 2.0 Providers: Introduction. http://msdn.microsoft.com/en-us/library/aa478948.aspx.

[ 3]

Zorrilla, Unai y Hernández, Octavio “El Marco de trabajo de entidades de ADO.NET 3.5 (III)”, dotNetManía nº 45, marzo de 2007.

[ 4]

Zorrilla, Unai y Hernández, Octavio “El Marco de trabajo de entidades de ADO.NET 3.5 (VI)”, dotNetManía nº 49, junio de 2007.

[ 5]

Zorrilla, Unai, Hernández, Octavio y Quintás, Eduardo. ADO.NET Entity Framework. Aplicaciones y servicios centrados en datos. Krasis Press, 2008.


entity framework

César de la Torre

Entity Framework en aplicaciones

con arquitectura N-Tier y N-Layer ADO.NET Entity Framework, que es parte de .NET Framework a partir de la versión 3.5 SP1, es una plataforma de acceso a datos que hace transparente para el desarrollador el sistema gestor de bases de datos al que ataca (SQL Server, Oracle, etc.). El objetivo de este artículo es muy práctico: responder a la pregunta ¿cómo podemos utilizar Entity Framework en aplicaciones con arquitectura N-Tier o N-Layer?

César de la Torre trabaja actualmente en Microsoft como Architect Advisor dentro de la División de Desarrolladores y Plataforma de Microsoft. Su background es fundamentalmente la arquitectura y desarrollo de aplicaciones distribuidas, con tecnología Microsoft, durante más de 11 años. Blog: http://blogs. msdn.com/cesardelatorre.

Antes de nada, vamos a definir qué entendemos por arquitecturas N-Tier y N-Layer. Una aplicación N-Tier es una aplicación basada en tres o más niveles físicos, como nivel de cliente/presentación, nivel de servidor de componentes de negocio y nivel de datos (servidores de bases de datos, etc.). Actualmente también hacemos uso de servicios Web (o, mejor incluso, específicamente de servicios WCF) para comunicar el nivel cliente/presentación con el nivel de servidor de componentes. La figura 1 muestra un diagrama típico de arquitectura N-Tier. Es un diagrama que me costó bastante encontrar, porque es de una presentación de Microsoft de aproximadamente 1998, en la época de Windows NT 4.0 y MTS (Microsoft Transaction Server), y poco después Windows DNA y COM+. Sin embargo, aunque las tecnologías internas han cambiado mucho en estos años, la arquitectura básica de estos niveles físicos (tiers) es la misma ☺. Como se puede observar, en una arquitectura N-Tier las aplicaciones cliente (bien basadas en Windows Forms, WPF o incluso Silverlight) necesitan acceder remotamente al nivel de servidor de aplicaciones haciendo uso, por ejemplo, de servi-

Figura 1

cios WCF. Relativo a esto, en mi opinión, las aplicaciones RIA (Rich Internet Applications) son un tipo especial de aplicaciones N-Tier. Otro tema diferente es que probablemente habremos diseñado nuestras aplicaciones como aplicaciones N-Layer (N-Capas), es decir, con varias capas lógicas en las que implementamos diferentes tipos de tareas. Por ejemplo, podemos tener capas como DAL (Data Access Layer), la capa BLL (Business Logic Layer), la capa BFLL (Business Façade Logic Layer), la capa de servicios WCF y una o varias capas de presentación (interfaz de


Figura 2

Figura 3

usuario), dependiendo del patrón que usemos, como MVC (Modelo-VistaControlador), MVP (Modelo-Vista-Presentador), MV-VM (Modelo-Vista-Vista Modelo), etc. Por supuesto, dentro de dicha arquitectura N-Layer, usted podrá suponer que Entity Framework (en adelante EF) encaja inicialmente en la capa DAL (Data Access Layer), donde se accede a los orígenes de datos, así como también haciendo uso de entidades desconectadas de EF, las cuales se pasarán/comu-

nicarán de unas capas de la arquitectura a otras. La figura 2 muestra un diagrama típico de arquitectura N-Layer. Y en la figura 3 vemos situadas en las capas las diferentes tecnologías de Microsoft, donde resalto la utilización de EF en la capa de acceso a datos en la parte inferior de la arquitectura. Por cierto, quiero resaltar que no todas las aplicaciones N- Layer tienen que ser aplicaciones N-Tier (niveles físicos, con nivel de presentación/cliente remoto), aunque todas las aplicaciones N-Tier sí deberían haber sido

diseñadas en modo N-Layer (capas lógicas diferenciadas). Quiero decir con esto que, en algunos casos, en cuantos menos niveles físicos tengamos dividido nuestro modelo, mejor rendimiento tendremos; por ejemplo, en una aplicación ASP.NET tendremos la mayoría de las veces la capa de presentación y la de componentes de negocio en el mismo servidor, como parte de un único nivel físico. Muchos niveles físicos pueden ser buenos para conseguir una óptima escalabilidad, sin embargo no favorecen el rendimiento puro debido a razones de latencia en las llamadas remotas. En cualquier caso, recuerde que NLayer tiene que ver con capas lógicas. Si volvemos a una arquitectura NTier (niveles físicos), como dije antes, necesitamos de mecanismos de acceso remoto (como WCF) para poder comunicar el nivel de cliente (por ejemplo una aplicación WPF o Silverlight) con el nivel de servidor de aplicación. Posteriormente, cuando se realizan consultas desde el servidor de componentes de negocio a la base de datos para obtener datos, como por ejemplo un pedido, lo obtendremos como una entidad de EF. Entonces lo desconectamos (detach) de su contexto de EF, se serializa automáticamente por WCF y se manda como entidad desconectada por la red (gracias a los servicios WCF) hasta llegar al nivel de presentación (aplicación y máquina cliente). Así pues, la mayoría de las aplicaciones empresariales usan patrones de arquitectura que necesita de una fachada sin estados para su lógica de negocio (como aplicaciones N-Tier y NLayer). Tendremos pues escenarios con orientación a servicios, con servicios Web básicos o servicios WCF, aplicaciones ASP.NET, aplicaciones tradicionales de escritorio Windows (cliente rico basado en Windows Forms o WPF) o incluso aplicaciones RIA con Silverlight que consumen servicios WCF, etc. En la mayoría de estos casos se trabaja con una filosofía de acceso a datos basada en “entidades de datos desconectadas”. Esto es bueno porque se consiguen aplicaciones altamente escalables, pues los datos de la base de datos (en las tablas reales) no sufren bloqueos mientras los usuarios están traba-

<<dotNetManía

<< dnm.entityframework

47


<< dnm.entityframework

jando en el nivel cliente (por ejemplo, un formulario WPF o Silverlight). Por ejemplo, en dicha aplicación cliente el usuario podría estar trabajando, cambiando datos de forma “desconectada”, y podría incluso irse diez minutos a tomarse un café mientras el formulario está abierto con los datos, volver, y finalmente actualizar los datos en el sistema central (servidor de aplicaciones). En ese momento, lo que pasará es que al final de una cadena de llamadas (pasando por servicios Web, componentes de negocio, etc.), una clase de la capa DAL, haciendo uso de “LINQ to Entity Framework”, actualizará dichos datos en la base de datos. ¿Correcto? Bueno, si hacemos simplemente esto, sería una actualización de tipo “El último gana”, o lo que yo llamo “Actualización muy optimista” ☺. Me explico. En muchas aplicaciones en las que no tengamos requisitos muy exigentes/complejos a nivel de actualizaciones, el sistema que hemos comentado puede ser suficiente. Pero en cambio, podemos tener otras aplicaciones donde el usuario necesita saber si los datos que está usando en la aplicación cliente han cambiado en la base de datos mientras él estaba trabajando (o tomando un café) con el formulario abierto y antes de actualizar los datos. En ese caso, deberemos hacer uso de “actualizaciones con concurrencia optimista”, manejando las posibles “excepciones de concurrencia optimista”. En este artículo nos referiremos al primer caso; vamos a ver cómo realizar actualizaciones de datos del tipo “El último gana” en aplicaciones N-Tier (con aplicación cliente remota y datos desconectados). Para cubrir el otro escenario, más avanzado, es posible que escriba un próximo artículo; en cualquier caso, al final de éste tenéis una referencia a mi blog [1], donde ese escenario lo tengo también contemplado. Bien, pues a nivel de tecnología, estamos hablando de: • Uso de Entity Framework y LINQ to Entities en nuestra capa DAL. • WCF como tecnología de comunicaciones remotas y orientación a servicios. • Cualquier tecnología .NET remota (WPF, Windows Forms, OBA o incluso Silverlight) para el nivel de presentación (interfaz de usuario con ejecución en máquina cliente).

<<dotNetManía

Opción base: actualización de datos en aplicaciones N-Tier haciendo uso de EF y entidades desconectadas

48

Para entender completamente lo que quiero decir, inicialmente vamos a explicar la forma más sencilla, es decir, cómo implementar actualizaciones simples

de datos en aplicaciones N-Tier haciendo uso de Entity Framework. Así pues, éste es el caso llamado “El último gana” o “Actualización muy optimista”. En este caso, no es necesario gestionar las posibles situaciones de concurrencia optimista. Primeramente, tendremos una clase de acceso a datos, CustomerDal, donde haremos uso de EF y LINQ to Entities para realizar la consulta inicial a la base de datos; por ejemplo, digamos que vamos a obtener los datos de un cliente y devolver dichos datos al nivel cliente/presentación mediante un servicio WCF. Generalmente, se tiene una o más clases de negocio (BLL) entre el servicio WCF y la clase DAL (invocaciones intermedias); en aras de simplificar el artículo, aquí la obviamos. El código de dicha clase DAL sería similar al que muestra el listado 1. public class CustomerDal { private MyDataBaseEntities context; public CustomerDal() { context = new MyBaseEntities(); } public Customer GetCustomer(string customerID) { var q = from c in context.Customers where c.CustomerID == customerID select c; var customer = q.First(); context.Detach(customer); return customer; } } Listado 1

Probablemente, una muy buena opción sería usar tipos genéricos en las clases de acceso a datos, para así no tener que repetir código parecido para distintas entidades; eso también lo obvio, por simplificar y hacer hincapié solo en la parte relativa a la actualización de datos desconectados en aplicaciones N-Tier. Si conoce algo de LINQ to Entities, estará de acuerdo conmigo en que el código de arriba es muy sencillo. Lo importante a destacar de este código es que estamos devolviendo un objeto de entidad desconectada, pasándolo a las capas lógicas superiores (DAB ->BLL -> Capa servicios WCF -> Presentación). Eso significa que de cara a EF estaremos tratando los objetos ObjectContext como “contextos de vida corta”. Básicamente, cuando se devuelva dicha


<< dnm.entityframework

entidad al servidor con los datos modificados, tendremos que hacer una reconexión (re-attach) de dicha entidad mediante un nuevo objeto de contexto, puesto que la entidad fue modificada en un estado desconectado. Este escenario es muy típico siempre que usemos fachadas sin estado (como hace la mayoría de las aplicaciones N-Tier y N-Layer). Volviendo a nuestro código, después podríamos tener un servicio WCF encargado de serializar y devolver dicha entidad desconectada.

[ ] NOTA

<<dotNetManía

En la siguiente versión de EF, será posible utilizar “clases de entidad” propias para ser transportadas por WCF. Esto es mejor de cara a sistemas SOA completamente interoperables, donde es preferible que las clases de entidad que se serialicen sean completamente “agnósticas” con respecto al sistema de acceso a los datos (EF).

50

El código del contrato de la operación de servicio WCF para recuperar un cliente se muestra en el listado 2. Hay que destacar que los métodos de servicios Web deben ser lo más ligeros posibles (simplemente son un interfaz de entrada externa); por eso, nuestro método del servicio Web está simplemente invocando a una clase de negocio (CustomerBll). La clase BLL es donde situaríamos código de lógica de negocio, seguridad, transacciones, etc.; pero en este caso es tan simple que consiste en un único método que llama a la clase DAL y devuelve lo mismo (lo que normalmente se llama en inglés Man in the middle). Por esta razón obvio su presentación. Después de eso, la aplicación cliente consumirá dicho servicio WCF y mostrará los datos de la entidad (los datos de un cliente, en este caso), por ejemplo en un formulario WPF. Recordad ahora que la aplicación cliente está

// Contrato WCF [OperationContract] Customer CustomerBll_GetCustomer(string customerID); // Implementación del método public Customer CustomerBll_GetCustomer(string customerID) { return new CustomerBll().GetCustomer(customerID); } Listado 2

trabajando con un objeto de entidad que está desconectado, por lo que no tenemos ningún ObjectStateManager de EF registrando los cambios. Veremos después cómo afecta esto. Así pues, una vez que los datos están visibles en el formulario, el usuario puede modificar los datos hasta que decida actualizarlos, pulsando, por ejemplo un botón “Grabar”. En este momento, la aplicación cliente llamará a otro método de WCF con un código similar al del listado 3. El método WCF llama a la clase de negocio y ésta a su vez a la clase de acceso a datos, que es donde tendremos el código interesante de LINQ to Entities y donde vamos a ver cómo utilizar EF para actualizar la entidad modificada que nos viene “desconectada” desde la aplicación cliente.

// Método de la clase DA L (acceso // a datos) public void UpdateCustomer( Customer customer) { // (CDLTLL) Debemos primero // “conectar” la entidad al contexto // Hago uso de un método EXTENSOR // propio para entornos desconectados // (N-Tier, etc.) // A ttach(customer) no funcionaría context.A ttachUpdated(customer); context.SaveChanges(); }

Listado 4

// Método WCF [OperationContract] Customer CustomerBll_UpdateCustomer(Customer customer); // Implementación del método: public void CustomerBll_UpdateCustomer(Customer customer) { new CustomerBll().UpdateCustomer(customer); } Listado 3

El listado 4 muestra el método de actualización de la capa DAL (recuerde que en este caso no tenemos que tratar las situaciones de concurrencia optimista).

Para poder aplicar cualquier actualización en la base de datos usando context.SaveChanges(), primero necesitamos tener la entidad ligada a ese contexto. Si simplemente utilizáramos una


<< dnm.entityframework

do context.TryGetObjectByKey, y eso es lo que establecemos como valores originales de esa entidad para el contexto actual. Entonces, llamamos al método context.A pplyPropertyChanges, proporcionando nuestra nueva entidad (con datos cambiados). Lo que hace EF es comparar los “datos originales” (datos actuales en la base de datos) con nuestros datos en la entidad que viene del cliente, y entonces actualiza en el contexto todas los cambios de propiedades/campos de nuestra entidad. Después de eso, ya podremos llamar a context.SaveChanges en el método principal. Ahí, EF

// Método extensor para contectar entidades desconectadas public static void A ttachUpdated(this ObjectContext context, EntityObject objectDetached) { if (objectDetached.EntityState == EntityState.Detached) { object currentEntityInDb = null; if (context.TryGetObjectByKey(objectDetached.EntityKey, out currentEntityInDb)) { context.A pplyPropertyChanges( objectDetached.EntityKey.EntitySetName, objectDetached); // A plicamos los cambios en propiedades a todas las // entidades referenciadas en el contexto context.A pplyReferencePropertyChanges( (IEntityWithRelationships)objectDetached, (IEntityWithRelationships)currentEntityInDb); } else { throw new ObjectNotFoundException(); } } }

Listado 5

Bueno, con este código ya hacemos cosas más especiales. En primer lugar, en nuestro código tenemos que determinar qué datos nuevos hay en nuestra entidad, es decir, cuáles serían los cambios si lo comparamos con los datos actuales en la base de datos. Para saber eso, necesitamos hacer una consulta a la base de datos y obtener los datos actuales. Lo hacemos mediante el méto-

do extensor que aplica los cambios de propiedades de mi entidad, pero en todas las entidades referenciadas dentro de nuestro modelo EF (Customer podría estar relacionado con Order, etc.), siempre y cuando estas otras entidades estén presentes en el grafo de datos del contexto actual. Este método es sumamente importante; en caso contrario, tendríamos algo que solo valdría para entidades completamente aisladas. El código de A pplyReferencePropertyChanges se presenta en el listado 6. Con esto, ya habríamos acabado. Pero aún mostraremos otra alternativa para implementar la estrategia “El último en

// Método extensor para tener en cuenta otras entidades del grafo public static void A pplyReferencePropertyChanges( this ObjectContext context, IEntityWithRelationships newEntity, IEntityWithRelationships oldEntity) { foreach (var relatedEnd in oldEntity.RelationshipManager.GetA llRelatedEnds()) { var oldRef = relatedEnd as EntityReference; if (oldRef != null) { // Este extremo es una referencia, no una colección var newRef = newEntity.RelationshipManager.GetRelatedEnd( oldRef.RelationshipName, oldRef.TargetRoleName) as EntityReference; oldRef.EntityKey = newRef.EntityKey; } } }

Listado 6

sí detectará los cambios con respecto a la base de datos y será posible actualizar la base de datos real (SQL Server, por ejemplo) con los nuevos datos. Quiero destacar que después de llamar a A pplyPropertyChanges también estoy llamando a A pplyReferencePropertyChanges. Para este caso sencillo, no es realmente necesario, pero explico qué es. Este método es también otro méto-

actualizar gana”. El resultado final es similar, pero sin embargo nos ahorraríamos hacer una consulta a la base de datos para conocer los datos actuales (no ejecutaríamos el método context.TryGetObjectByKey). En cambio, lo que hacemos es “decirle” al contexto que “todas las propiedades de mi entidad han cambiado, simplemente porque yo lo digo”. Después de eso, simplemente llamaremos de

<<dotNetManía

llamada al método predefinido context.A ttach(customer), la cosa no funcionaría, porque la entidad customer es desconocida en el nuevo contexto que tenemos: este nuevo objeto de contexto no sabe nada de esta entidad, es decir, no tiene registrado ningún cambio que se haya producido sobre ella. Por esta razón es por la que he creado un método extensor propio para ObjectContext llamado A ttachUpdated . Este método permite enlazar/conectar objetos de entidad que vienen, desconectados, de la aplicación cliente remota. Su código se presenta en el listado 5.

51


<< dnm.entityframework

En muchos casos, la estrategia “El último gana” sería incluso lo deseable; pero en otros puede ser inaceptable

igual forma a context.SaveChanges, y en este caso se actualizarán todas las propiedades/campos de la entidad. Simplemente “porque yo lo he dicho” ☺. He implementado esta técnica por medio de otro método extensor, SetA llModified, en este caso asociado a la entidad en lugar del contexto (listado 7). Usando este método extensor, el código para la actualización de un cliente quedaría tan simple como se ve en el listado 8.

Esta sería la otra opción que tenemos para actualizaciones simples de tipo “El último gana”. La ventaja, como ya hemos mencionado, estriba en que no necesita consultar a la base de datos para conocer los datos originales. La desventaja: que si tenemos muchas propiedades/campos en la entidad, actualizaremos siempre todas las propiedades del registro, aun cuando el usuario hubiera cambiado solo un campo o unos pocos. Dependien-

// Método extensor de la entidad para decir que se han modificado // todas las propiedades public static void SetA llModified<T>(this T entity, ObjectContext context) where T : IEntityWithKey { var stateEntry = context.ObjectStateManager. GetObjectStateEntry(entity.EntityKey); var propertyNameList = stateEntry.CurrentValues.DataRecordInfo.FieldMetadata. Select(pn => pn.FieldType.Name); foreach (var propName in propertyNameList) { stateEntry.SetModifiedProperty(propName); } }

public void UpdateCustomer( Customer customer) { context.A ttach(customer); customer.SetA llModified(context); context.SaveChanges(); } Listado 8

do de cada caso concreto, podemos utilizar un camino u otro. ¡Fenómeno! Pues eso parece sencillo, “y vivimos en un mundo siempre feliz”. ¿Seguro? Bueno, pues depende, porque como dije al principio del artículo, esta forma de actualizar los datos no cubre escenarios en los que queramos gestionar actualizaciones con concurrencia optimista. Retomando nuestro caso de uso, supongamos que mientras el usuario original estaba tomándose su café, otro usuario utiliza la aplicación y actualiza datos del mismo cliente en la base de datos. ¿Qué pasará cuando el primer usuario vuelva y pulse el botón “Grabar”? Pues lo dicho, el usuario original ni se enterará de va a sobrescribir modificaciones que ha hecho un segundo usuario, y de hecho, machacará dichos datos (“El último gana”). En muchos casos, esto sería incluso lo deseable; pero en otros puede ser inaceptable. Todo depende del caso concreto. Como ya hemos mencionado, para un análisis de este segundo tipo de situación, en la que es necesario gestionar las actualizaciones con concurrencia optimista y sus excepciones, podéis consultar mi blog [1], donde explico en detalle una implementación de dicho escenario.

Listado 7

Bibliografía

<<dotNetManía

[ 1]

52

Post en el blog de César de la Torre en el que se describe el escenario basado en concurrencia optimista: “Optimistic Concurrency Updates using Entity Framework in N-Tier and N-Layer Applications”, en http://blogs.msdn.com/cesardelatorre/ archive/2008/09/05/optimistic-concurrency-updates-using-entity-framework-in-n-tier-and-n-layer-applicationspart-2.aspx.


q&a

Alberto Población lleva 29 años desarrollando software. Es MCSE, MCDBA, MCITP, MCSD, MCPD y MCT, además de MVP de C#. Alberto trabaja como consultor independiente, dedicándose principalmente a la formación, asesoramiento y desarrollo de aplicaciones.

Herencia de controles

en Windows Forms ¿Cómo podría hacer que un TextBox presente en mayúsculas todos los caracteres tecleados? ¿Y hacer que solo acepte números?

Tenemos aquí dos ejemplos de preguntas en las que se pide modificar o extender el comportamiento de uno de los controles originales de Windows Forms. En algunos casos, la solución es muy simple a partir de las propiedades o eventos de los controles. Por ejemplo, hacer que el TextBox funcione en mayúsculas puede conseguirse poniendo el valor CharacterCasing.Upper en su propiedad CharacterCasing. Sin embargo, no siempre las cosas son tan sencillas. Se podría hacer que el TextBox solo aceptase números manipulando alguno de sus eventos, como por ejemplo KeyUp. Pero el código comienza a complicarse, sobre todo si buscamos para el control algún comportamiento más sofisticado que el simple rechazo de ciertos caracteres, y pronto nos encontramos con un formulario salpicado de procedimientos de tratamiento de eventos que tenemos que acordarnos de conservar y modificar junto con los controles cuando cambiemos algo en la interfaz de usuario. Cuando los controles estándar no satisfacen con eficacia nuestros requisitos, es el momento de comenzar a pensar en crear nuestros propios controles. Para ello tendremos que crear una clase que herede, directa o indirectamente, de la clase Control. Si heredamos directamente de Control, la clase base únicamente dibujará un rectángulo en blanco, y tendremos que escribir todo el código necesario para dibujar el control, así como para implementar su comportamiento. Otra posibilidad, con la que ya están familiarizados muchos desarrolladores, es la de here-

dar de UserControl (que a su vez hereda indirectamente de Control). En este caso estamos creando lo que se denomina un “control de usuario”, que básicamente consiste en un contenedor para albergar otros controles ya existentes más el código asociado a los mismos. Visual Studio soporta específicamente este tipo de controles, permitiendo dibujarlos desde el diseñador como si se tratase de formularios Windows. Gracias a estas herramientas visuales, la creación de controles de usuario es muy sencilla, y no nos vamos a ocupar ahora mismo de ellos. Finalmente, una tercera alternativa bastante común es la de heredar de uno de los controles ya existentes para extender o modificar su comportamiento. Aplicando esta técnica, vamos a heredar de la clase TextBox y suplantar (redefinir, sobrescribir) el método OnKeyPress de forma que rechacemos la tecla pulsada cuando no corresponda a un carácter numérico. El primer paso consistirá en crear nuestra clase, bien sea dentro del mismo proyecto Windows Forms que la va a utilizar, o bien en una librería de clases independiente que luego podremos utilizar desde múltiples proyectos. La labor se ve facilitada gracias a que Visual Studio nos permite añadir el código a nuestro proyecto sin más que seleccionar la correspondiente plantilla (“Custom Control”). Nos encontraremos con una clase en la que modificaremos la herencia para que descienda del control que hemos elegido, en nuestro caso TextBox (listado 1). Dentro de esta clase, suplantaremos los métodos que nos interesen para modificar el comporta-

<<dotNetManía

dnm.q&a

dnm.q&a

dnm.q&a

Alberto Población

53


<< dnm.q&a public partial class TextBoxNumerico : TextBox { } Listado 1

public partial class TextBoxNumerico : TextBox { protected override void OnKeyPress(KeyPressEventA rgs e) { char c = e.KeyChar; if (c >= ‘0’ && c <= ‘9’ || c == (char)8) { e.Handled = false; return; } e.Handled = true; } public override string Text { get { return base.Text; } set { Regex re = new Regex(@”^\d*$”); if (re.IsMatch(value)) base.Text = value; } } } Listado 2

miento del control original. En este caso, como ya hemos dicho, es el método OnKeyPress el que debe rechazar ciertos caracteres. Para ello, será suficiente con devolver el valor Handled=True a través del parámetro KeyPressEventA rgs que recibe nuestro OnKeyPress. Con esto notificamos a la clase base que ya nos hemos encargado de procesar el carácter, con lo que no se realiza sobre él ningún tratamiento adicional y resulta despreciado. El listado 2 muestra el código correspondiente.

Observe que, además de los caracteres numéricos, hemos aceptado también el carácter con código 8, que corresponde a la tecla de retroceso, para que el usuario pueda borrar caracteres mientras teclea. También hemos suplantado la propiedad Text heredada del TextBox original, con el fin de rechazar las cadenas que contengan caracteres no numéricos cuando sean asignadas a nuestro TextBox desde código a través de esta propiedad.

Una vez compilada la clase TextBoxNumerico, bastará con hacerla visible desde nuestro proyecto Windows Forms (añadiendo una referencia en caso de haberla compilado en una DLL separada), y podremos arrastrar el nuevo cuadro de texto a nuestro formulario Windows desde la barra de herramientas (figura 1).

Figura 1

Si planeamos utilizar este control con frecuencia, podemos añadirlo a un pestaña de la barra de herramientas, haciendo clic sobre ésta con el botón derecho y seleccionando desde el menú de contexto la opción que nos permite añadir nuevos elementos. Desde aquí elegiremos la DLL que contiene nuestra clase, y el control quedará permanentemente incorporado a las herramientas. Si queremos personalizar el icono que aparece en la barra, podemos opcionalmente decorar la clase con el atributo ToolboxBitmap para indicar el icono deseado. Terminadas estas operaciones, podremos utilizar nuestro control personalizado en cualquier proyecto como si fuera uno de los controles nativos de .NET Framework.

<<dotNetManía

¿Cómo podría cambiar el color de frente (ForeColor) de un TextBox cuya propiedad Enabled sea false? De forma predeterminada, el texto se presenta en color gris y resulta poco visible.

54

La respuesta más sencilla suele ser la de utilizar la propiedad ReadOnly en lugar de Enabled. De esta manera, el texto aparece en color negro y es más

fácilmente visible. No obstante, esta solución no es perfecta, dado que no se puede seleccionar cualquier color deseado, y además el comportamien-

to en cuanto a tabulación y ubicación del cursor no es el mismo que cuando se usa Enabled=False. Para remediarlo, hay que manipular además la


<< dnm.q&a

Figura 2

dibujar (propiedad Text heredada de la clase base), el mismo Font que también heredamos, la brocha, y el rectángulo dentro del que debe dibujar, que nos llega como propiedad del argumento PaintEventA rgs recibido por OnPaint. Al igual que el resto de instrucciones de dibujo de GDI+, el método DrawString debe ejecutarse sobre un objeto de la clase Graphics que, de la misma manera que ClipRectangle, se recibe a través del argumento de nuestro método. Si ahora compilamos el código, añadimos el control sobre un formulario, y lo ejecutamos, lamentablemente observaremos que no hemos conseguido nada. Nuestro TextBox continúa presentando el mismo aspecto del original, y si seguimos la ejecución del código con el depurador encontraremos que no entra nunca en nuestro método OnPaint. La razón es que nos falta habilitar en nuestro control el estilo “dibujado por el usuario”. Esto se consigue con una llamada a SetStyle en el constructor (listado 2).

Volvemos, por tanto, a encontrarnos en una situación como la de la pregunta anterior, en la que los controles estándar no satisfacen por completo nuestros requisitos. Una vez más, recurriremos a la solución de crear una clase hija y suplantar dentro de ella la funcionalidad pertinente. Crearemos, como en el caso del cuadro de texto numérico, una clase hija de TextBox, y en ella suplantaremos los métodos que nos interesen para modificar el comportamiento del control original. En este ejemplo concreto, deseamos cambiar la forma en que se dibuja el TextBox, para lo cual emplearemos el método OnPaint. El listado 1 presenta una primera aproximación. Dentro del método OnPaint, en primer lugar llamamos al correspondiente OnPaint de nuestra clase base, que realizará el dibujo “ordinario” del TextBox. A continuación comprobamos si la propiedad Enabled vale False, y en ese caso dibujamos nuestro propio texto sobre el cuadro de texto. Para pintar el texto en otro color, hemos creado una brocha (Brush b) con el mismo color que ya está especificado en la propiedad ForeColor del TextBox que hemos heredado. Seguidamente, hemos llamado a la instrucción DrawString de GDI+, pasándole el texto a

Ahora sí, si volvemos a ejecutar el programa que contiene nuestro cuadro de texto, aunque éste tenga Enabled=False, el texto aparecerá en el color que hayamos establecido como ForeColor. Pese a que lo anterior funciona, el comportamiento todavía no es idéntico al del TextBox normal. El color de fondo queda en blanco, y el texto no se amolda al rectángulo del cuadro de texto en la forma que esperamos. Para remediar el primer problema, utilizaremos la instrucción FillRectangle para rellenar el fondo con el color deseado (que en el TextBox original es KnownColor.Control, pero podríamos fácilmente sustituir por un color diferente). El lugar idóneo para llevar a cabo esta operación es el método OnPaintBackground, que quedará como muestra el listado 3.

protected override void OnPaint(PaintEventA rgs e) { base.OnPaint(e); if (!this.Enabled) { using (Brush b = new SolidBrush(this.ForeColor)) { e.Graphics.DrawString(this.Text, this.Font, b, e.ClipRectangle); } } }

protected override void OnPaintBackground( PaintEventA rgs e) { base.OnPaintBackground(e); if (!this.Enabled) { using (Brush b = new SolidBrush( Color.FromKnownColor(KnownColor.Control))) { e.Graphics.FillRectangle(b, e.ClipRectangle); } } }

Listado 1

public MiTextBox(): base() { this.SetStyle(ControlStyles.UserPaint, true); } Listado 2

Listado 3

<<dotNetManía

propiedad TabStop y/o recurrir a insertar código en distintos eventos del control para reaccionar ante el posicionamiento del cursor.

55


<< dnm.q&a En cuanto a la adaptación del texto al rectángulo, aprovecharemos que la instrucción DrawString dispone de un último parámetro opcional que permite configurar el modo de dar formato a la cadena. Como refinamiento adicional, contemplaremos también a través de dicho parámetro el caso de que el TextBox haya sido configurado en modo multilínea. Tras añadir estos cambios, nuestro OnPaint queda como se ve en el listado 4.

protected override void OnPaint(PaintEventA rgs e) { base.OnPaint(e); if (!Enabled) { StringFormatFlags ff = StringFormatFlags.NoClip; if (!this.Multiline) ff |= StringFormatFlags.NoWrap; using (Brush b = new SolidBrush(this.ForeColor)) { e.Graphics.DrawString(this.Text, this.Font, b, e.ClipRectangle, new StringFormat(ff)); } } } Listado 4

<<dotNetManía

Con todo esto, nuestro control personalizado queda casi listo para ser utilizado. Queda todavía una pega: no hemos previsto las instrucciones necesarias para dibujar el texto cuando el TextBox está habilitado (Enabled es verdadera), con lo que su contenido aparece vacío en este caso. Esto se puede remediar desactivando el modo de “dibujo por el usuario” cuando se recibe false en la propiedad Enabled (listado 5).

56

La forma más simple de redibujar el contenido de un control consiste en invalidar su zona cliente, con lo que se volverá a disparar el evento OnPaint. Para ello disponemos del método Invalidate

public new bool Enabled { get { return base.Enabled; } set { base.Enabled = value; this.SetStyle(ControlStyles.UserPaint, !value); this.Invalidate(); } }

Listado 5

Nótese que aquí hemos tenido que usar new en lugar de override, debido a que la propiedad Enabled de TextBox no está marcada como virtual. Cuando cambiamos el valor de esta propiedad, es necesario volver a dibujar el contenido del control. La forma más simple de conseguirlo consiste en invalidar su zona cliente, con lo que se volverá a disparar el OnPaint que dibujará de nuevo el contenido. Para ello disponemos del método Invalidate heredado de la clase madre, que hemos invocado en el set de nuestra propiedad Enabled, como se ve en el listado 5. Es importante recordar esta técnica, pues necesitaremos emplearla cada vez que añadamos a nuestro control alguna propiedad nueva de la que dependa el aspecto visual del control. Con este código, tenemos ya disponible un control que implementa gran parte de la funcionalidad de TextBox, y que además permite cambiar el color del texto cuando se encuentra en estado deshabilitado. Posiblemente con esto ya sea suficiente para utilizarlo en muchos proyectos. Si necesitamos perfeccionar algún otro de sus comportamientos, siempre podremos hacerlo mediante técnicas similares a las anteriores. En conclusión, heredar de un control que ya existe para modificar su comportamiento es algo muy eficaz y sencillo de llevar a cabo cuando la funcionalidad requerida es próxima a la de un control ya disponible. Si queremos cambiar el aspecto visual, necesitamos saber utilizar las instrucciones de GDI+ para dibujar el control en la forma deseada. Pero si el cambio que buscamos es más simple, por ejemplo, un TextBox que solo admita números pero no letras, el código necesario puede ser tan sencillo como un mero override de algunas propiedades y métodos. Quienes desarrollen aplicaciones para Windows Forms harán bien en tener presente esta técnica, pues puede facilitar mucho su trabajo en algunas ocasiones.


biblioteca.net Programming Entity Framework Julia Lerman Editorial: O'Reilly Media Páginas: 828 Publicado: febrero de 2009 ISBN: 978-0596520281 Idioma: inglés Excelente ha sido la acogida de los lectores a esta primera obra de Lerman, donde aporta un conocimiento enciclopédico de lo que puede y debe hacerse con el nuevo modelo de trabajo con datos propuesto por Microsoft. La autora (visite su blog en http://www.thedatafarm.com/blog) es bien conocida por sus numerosos artículos en MSDN Magazine. Más de un año consumido en su creación, todas las partes merecen la pena por el contenido y por el continente: claro, bien explicado, con ejemplos suficientes pero no gigantescos (en VB.NET y C#), abordando problemas del día a día y sin olvidarse de ninguno de los protagonistas del ciclo de vida de las aplicaciones. Las guías para la utilización real de EF en nuestras aplicaciones son de lo mejor de esta obra, porque aborda desde los supuestos típicos hasta situaciones de multiproceso, control de hebras de ejecución o mejoras del rendimiento. Totalmente recomendable.

Professional ADO.NET 3.5 with LINQ and the Entity Framework Roger Jennings Editorial: Wrox Páginas: 672 Publicado: febrero de 2009 ISBN: 978-0470182611 Idioma: inglés Sin llegar a la calidad técnica y estilística del anterior, se trata de una obra notable, dividida en dos partes: en los primeros 7 capítulos se explica profusamente cómo utilizar LINQ en todos los contextos donde esta tecnología tiene sentido y es más aprovechable, siempre con ejemplos en ambos lenguajes, e incluso presentando algunas tecnologías emergentes relacionadas o en fase inicial, como Parallel LINQ, LINQ to REST, LINQ To SharePoint (LINQ4SP) y LINQ to Active Directory (antes conocida como LINQ to LDAP, y disponible en http://www.codeplex.com/LINQtoA D). En la segunda parte, se aborda detalladamente la programación con Entity Framework, incluyendo EDM, Entity SQL y LINQ to Entities, utilizando ejemplos bastante cercanos al mundo real.

novedades

El autor es, por lo demás, un veterano escritor técnico de esta editorial, que siempre se ha enfocado en los mecanismos de acceso a datos como tema principal, así como en los lenguajes o plataformas que sirven como vehículos para ese acceso.

Murach’s ADO.NET 3.5, LINQ, and the Entity Framework with VB 2008 Anne Boehm. Editorial: Mike Murach & Associates. Páginas: 712. ISBN: 978-1890774523 . Fecha de publicación: marzo de 2009. Idioma: inglés.

Essential LINQ Charlie Calvert y Dinesh Kulkarni. Editorial: Addison-Wesley Professional. Páginas: 600. ISBN: 978-0321564160 . Fecha de publicación: marzo de 2009. Idioma: inglés.

TEXTO: MARINO POSADAS


desván

Marino Posadas

documentos en la red

<<dotNetManía

Crisis y “software factories”

58

La crisis nos acecha, de eso no hay duda. Sin embargo, hay empresas que parecen salir incluso reforzadas de este tipo de situaciones. Y no me refiero a aquellas que cuentan con subvenciones y/o avales del estado para hacer frente a sus problemas coyunturales. Estoy fijándome en aquellas que anuncian un incremento en sus ganancias frente a las hasta ayer directas competidoras que anuncian catástrofes. ¿Qué factor convierte la crisis en oportunidad? No es fácil la respuesta, claro, y menos en el terreno del software. Y líbreme Alan Turing (o quien sea) de pretender tener esa solución. Pero se aprecian patrones. Con o sin crisis, las empresas siguen teniendo necesidades. La diferencia está en la forma de cubrirlas. Con crisis o sin ella, la mayoría busca lo “bueno, bonito y barato”. Sin crisis, las palabras “buenas prácticas”, “construcción para extensibilidad” o “dinero invertido a medio plazo” tienen sentido. Cuando la crisis se nota, cambiamos a “rápido, bonito y barato”… o “rápido y barato” (¡qué le vamos a hacer!). Ahí es donde interviene nuestro protagonista de hoy. Pero no entendiendo la “software factory” como una máquina de hacer “churro-software”, sino como una actitud. La actitud de preparar las cosas para una optimización y extensibilidad máxima. La de aprovechar lo existente (¿reutilización?) para no tener que reinventarnos una y otra vez. Y la de saber integrar lo nuevo con lo viejo para aprovechar los valores que, siendo vetustos, cumplan su función, permitiendo crecer sobre lo existente. Dar soluciones a problemas, en suma, y hacerlo en el menor tiempo posible y con la mayor solidez y capacidad de adaptación al problema del cliente. Desde la perspectiva técnica, quizá sea –como dice Jack Greenfield (en la foto), en "The Case for Software Factories" (http://msdn.microsoft.com/enus/library/aa480032.aspx)– una cuestión de añadir un nivel más de abstracción, si bien eso no significa que el desarrollo de software se reduzca a un mero proceso mecánico, según él mismo afirma. Pero sí debe concienciarnos para saber utilizar mejor los preciosos recursos del programador experimentado. La componentización y el ensamblado desacoplado de las "piezas" de software que propugna la arquitectura SaaS es una buena aproximación, sin duda. El propio Greenfield, en una conferencia pronunciada en Gales, ponía como ejemplo a la empresa BMW, que raramente fabrica el mismo automóvil, pero no por eso renuncia a ser factoría (http://www.theregister.co.uk/ 2007/03/27/software_factories_greenfield). Y añade, "el reto consiste en saber captar cuáles son las necesidades propias del cliente, y suplirlas con el uso adecuado de herramientas y sistemas que automaticen entre el 40% y el 80% de esas necesidades". Volviendo a nuestro mundo, ¿qué herramienta mágica nos puede solucionar esas necesidades? Pues Visual Studio, según él mismo afirma en "Software Factories: Assembling Applications with Patterns, Models, Frameworks, and Tools" (ver http://www.amazon.com/Software-Factories-Assembling-Applications-Frameworks/dp/0471202843). Con esa intención, coordina con Rick LaPlante lo que va a ser la nueva versión de Visual Studio (2010). Lo de menos es que esté hecha en WPF. Lo verdaderamente importante es ese alineamiento, esa actitud productora, esa "garantía de continuidad en la innovación", que significa nuestra herramienta favorita. Por muchos años.

firma.firma.firma.firma

Research Channel es un canal de expresión reservado a la comunidad de investigación y desarrollo, donde participan miembros de Microsoft (que son muchos y muy activos). Son documentos principalmente visuales a los que se accede como presentación on-line. Allí podemos averiguar lo que va a venir, en qué estado se encuentra, qué se persigue con ello y en qué productos es posible que lo veamos implementado. Explicado por sus autores. http://www.researchchannel.org/ prog/displayinst.aspx?fID=880&pID=480. El SDK de Silverlight 3.0, disponible. Pues este es el segundo documento importante del mes que queremos recomendar, porque Silverlight sigue ganando adeptos día a día. De forma un tanto silenciosa, pero ahí está: http://www.microsoft.com/downloads/details.aspx? displaylang=en&FamilyID=d09b6ecf-9a45-4d99-b7522a330a937bc4. Incluye documentación. No obstante, el lector interesado deberá de estar atento a lo que se “cuece” en el Mix09, donde Silverlight alcanzaba la máxima cuota de sesiones (31), con mucha diferencia sobre sus inmediatos seguidores: UI/UX (18) y ASP.NET (14).

sitios del mes Community Bookmarks es un “sitio de sitios”. Almacena enlaces que apuntan a soluciones de desarrollo encontradas y publicadas por diferentes miembros de la comunidad de desarrollo. En poco tiempo ya ofrece más de 200 páginas o listados de enlaces. Es una iniciativa de MSDN disponible en el sitio http://social.msdn.microsoft.com/en-US/#sort=week& page=0&filter=allcontent. DZone Snippets es un sitio donde los usuarios suben pequeños fragmentos de código fuente de todos los orígenes y sabores que resuelven problemas concretos de desarrollo. Más de 15.000 usuarios han colaborado hasta el momento con el sitio, que está accesible en http://snippets.dzone.com/posts.

utilidades del mes MSDN Respuestas es un complemento para Visual Studio que nos permite buscar soluciones a los problemas diarios de desarrollo sin salir de casa… quiero decir del propio IDE. Muchas categorías disponibles y más que están por venir. Totalmente imprescindible. Es gratuito y descargable desde http://msdn.microsoft.com/eses/msdnrespuestas.aspx. gHacks.net. Más que una utilidad, un grupo de ellas, y todas relacionadas con navegadores, la impresión y formato de páginas y temas similares. Disponible en http://www.ghacks.net.



dotNetManía #058