Archivo de la etiqueta: entity framework

Transformando web.config (o app.config) para depuración

Una de las características más interesantes de los ficheros web.config, es que al publicarlos podemos aplicar una serie de transformaciones a los mismos, de tal manera que ciertos datos que estén en depuración no lleguen en modo release, y viceversa.

Sin embargo, hay casos en los que nos puede ser útil tener varios ficheros config para las diferentes configuraciones de build. En mi caso, desarrollando RealPoll, me di cuenta que esto podría ser interesante, y he creado tres configuraciones:

  • Debug_FakeDB
  • Debug_LocalDB
  • Debug_RemoteDB

Para cada una de las opciones tengo un fichero web.config diferente. El problema es que la transformación solamente se aplica al publicar, y no en el proceso de depuración, por lo tanto son poco útiles estos perfiles. Sin embargo, buscando un poco en internet encontré este artículo en CodeProject en cuyos comentarios estaba la respuesta a mi problema, modificar (a mano) el fichero csproj y agregar la siguiente directiva tras la compilación (tenemos un ejemplo comentado al final de nuestro proyecto):

<Target Name="AfterBuild">
   <TransformXml Source="Web.Base.config" Transform="Web.$(Configuration).config" Destination="Web.config" StackTrace="true" />
 </Target>

Una vez agregada, deberemos entonces duplicar la información de nuestro web.config (o app.config si desarrollamos una aplicación de escritorio) en un fichero llamado web.base.config (por ejemplo), ya que tras cada compilación el fichero web.config se regenerará.

Dentro de cada fichero de configuración, tenemos diferentes opciones. En el caso de debug_fakedb se agrega una clave a appsettings, que luego consulto al inicializar mi código:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings>
    <add xdt:Transform="Insert" key="FakeDB" value="true" />
  </appSettings>
</configuration>

Esta clave luego la consulto a la hora de inicializar el código:

if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["FakeDB"]) == false)
    Current.Bind<IQuestionRepository>().To<FakeQuestionRepository>();

else
    Current.Bind<IQuestionRepository>().To<DBQuestionRepository>();

Lo bueno de dejar estos valores en claves de configuración es que nos permite hacer cambios “en caliente” sin tener que recompilar la aplicación, como bien recomendaban Andy Hunt y Dave Thomas en su “Pragmatic Programmer”.

En el caso de localDB agregamos la información de Entity Framework (que ya sabrá que hacer):

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <entityFramework xdt:Transform="Insert">
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
</configuration>

Finalmente, para el caso de remoteDB, agregamos la información de Entity Framework, así como la cadena de conexión (que más adelante se sustituye en azure):

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <connectionStrings xdt:Transform="Insert">
      <add name="QuestionContext"
           connectionString="YOUR_CONNECTION_STRING_HERE"
           providerName="System.Data.SqlClient" />
  </connectionStrings>
  <entityFramework xdt:Transform="Insert">
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

Para mí supone un ahorro considerable de tiempo y esfuerzo, además de que me permite probar las diferentes configuraciones sin recompilar.

Si quieres verlo en ejecución, echa un vistazo al código de Realpoll en github del que hablaré muy, muy pronto.

¿Qué es un ORM y por qué nos interesa?

En el desarrollo de una aplicación suelen estar involucradas dos entidades diferentes, por una parte  el código que mueve la aplicación y por otra los datos que se manejan. Con el tiempo estas dos entidades han evolucionado de manera diferente, y el acceso a los datos desde los programas se ha vuelto una tarea en ocasiones, complicada. Los sistemas de Mapeo Objeto-Relacional u ORM ayudan a combatir esta complicación.

En este artículo se verá una definición de estos sistemas, así como algunos ejemplos de motores ORM empleados en la actualidad de manera comercial.

Origen de los conflictos: Las bases de datos relacionales

En un principio los programas accedían físicamente al disco para escribir los datos, algo que implicaba que el programa tuviese que implementar toda la lógica de una base de datos para permitir agregar, modificar o eliminar datos.

Con el tiempo se han desarrollado lo que se conoce como sistemas de bases de datos relacionales, que permiten mantener entidades (Artículo, Ficha médica o Factura), sus respectivas relaciones (Una ficha médica corresponde a un solo paciente) y sus atributos (Una ficha médica contiene fecha de entrada, fecha de salida, síntomas… etc).

Estos sistemas poseen además una interfaz para acceder a ellos llamada SQL o Structured Queried Language (lenguaje estructurado de consultas) que permiten hacer peticiones de una base de datos usando una notación muy similar a lenguaje natural, como muestra el siguiente ejemplo:

    select nombre,apellidos from pacientes where id_paciente = 1;

Este código tendría como objetivo hacer una petición a la base de datos pacientes, buscar el identificador 1 y devolver la fila (o filas) resultante de la petición.

Estos sistemas permiten mantener cierta integridad de los datos, y usando ciertas reglas se pueden definir tablas y restricciones como muestra el siguiente ejemplo:

    create database pacientes(
        id_paciente int,
        nombre varchar(80),
        apellidos varchar(120)
    );

Entre los sistemas gestores de bases de datos más utilizados se encuentran:

  • SQL Server de Microsoft: Es la solución por excelencia del stack Microsoft. Existen al menos una docena de ediciones diferentes dirigidas a un público específico, desde la versión Express, gratuita y con limitaciones (1 GB de consumo de memoria y 4 GB de capacidad) hasta la Datacenter, que permite el uso de 256 núcleos (poca cosa…)  y dirigida a un mercado empresarial.
  • mySQL: Anteriormente propiedad de Sun Microsystems y con doble licencia (libre para proyectos compatibles con la licencia GNU GPL y privativa para el resto de los proyectos, que implica la compra de una licencia), actualmente propiedad de Oracle, es la base de datos más empleada por la comunidad OpenSource (+6.000.000 de instalaciones).
  • PosgreSQL: Empleada en ámbito docente aunque no por ello menos potente que la anterior, libre (licencia BSD) y mantenida por la comunidad de desarrolladores.
  • Oracle: Considerado por muchos uno de los sistemas de bases de datos más complejos, usado fundamentalmente en el mercado de servidores empresariales donde su hegemonía ha sido casi total hasta hace poco, por la competencia del resto de sistemas antes mencionados. Posee también una versión Express (gratuita)

Antes de los ORM

Antes de la aparición de estos sistemas las consultas se tenían que realizar a mano dentro de las propias aplicaciones, con lo cual la ventaja de los lenguajes orientados a objetos se perdía, ya que había que crear una petición a la base de datos de manera manual (y específica para cada sistema, ya que no todos los gestores de bases de datos tienen la misma implementación del lenguaje SQL).

Para muestra, un ejemplo que se puede encontrar en la documentación del lenguaje PHP:

// El siguiente código puede ser proporcionado por el usuario, a modo de ejemplo
$firstname = 'fred';
$lastname  = 'fox';

// Formular Consulta
// Este es el mejor método para formular una consulta SQL
// Para más ejemplos, consulte mysql_real_escape_string()
$query = sprintf(&quot;SELECT firstname, lastname, address, age FROM friends
    WHERE firstname='%s' AND lastname='%s'&quot;,
    mysql_real_escape_string($firstname),
    mysql_real_escape_string($lastname));

// Ejecutar Consulta
$result = mysql_query($query);

// Comprobar resultado
// El siguiente código muestra la consulta enviada a MySQL y el error ocurrido. Útil para debugging.
if (!$result) {
    $message  = 'Invalid query: ' . mysql_error() . &quot;\n&quot;;
    $message .= 'Whole query: ' . $query;
    die($message);
}

// Usar resultado
// Si intenta imprimir $result no será posible acceder a la información del recurso
// Una de las funciones mysql result debe ser usada
// Consulte también mysql_result(), mysql_fetch_array(), mysql_fetch_row(), etc.
while ($row = mysql_fetch_assoc($result)) {
    echo $row['firstname'];
    echo $row['lastname'];
    echo $row['address'];
    echo $row['age'];
}

// Libere los recursos asociados con el resultset
// Esto es ejecutado automáticamente al finalizar el script.
mysql_free_result($result);

Como se aprecia, es necesaria una adaptación de los datos a la aplicación además del aprendizaje del lenguaje de gestión de las bases de datos.

El mapeo relacional

La ventaja principal de estos sistemas es que reducen la cantidad de código necesario para lograr lo que se conoce como una persistencia de objetos

Esto permite además, lograr una integración con otros patrones como el Modelo-Vista-Controlador, donde el modelo puede ser este objeto. En el ejemplo siguiente se muestra cómo se define un modelo usando Doctrine, uno de los sistemas ORM más usados para PHP, donde se muestra el tipo usuario y los campos username y password. Será el propio sistema el que se encargue de convertir esta información a tablas SQL y a realizar el procesamiento, mientras que nosotros trabajaremos fundamentalmente con objetos

class User extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this-&gt;hasColumn('username', 'string', 255);
        $this-&gt;hasColumn('password', 'string', 255);
    }
}

Este otro ejemplo, que usa ADO.net Entity Framework, el ORM de .NET, se pueden apreciar también la facilidad para establecer propiedades a campos, como en este caso establecer obligatoriedad.

namespace MyApp.Models
{
    public class User
    {
        public int Id { get; set; }
        [Required] public string UserName { get; set; }
        [Required] public string Password { get; set; }
    }
}

Motores de persistencia

Estos son algunos motores de persistencia a los que he podido echar un vistazo, algunos forman parte de frameworks más potentes (Como Core Data en el caso de iOS) y otros son independientes (como el anteriormente mencionado Doctrine), aunque todos comparten la misma base, dar un modelo de persistencia de objetos.

  • C#: Entity Framework es un conjunto de APIs que proporcionan acceso a datos en .NET. Se distribuye junto con el .NET framework y tiene 3 posibles modos de trabajo, Database First, Model First y Code First, más información en el sitio oficial
  • Java: Hibernate es una herramienta de mapeo relacional para la plataforma Java, que emplea atributos declarativos mediante XML o anotaciones, se distribuye con licencia GNU/LGPL y posee una versión para .NET llamada nHibernate, más información en el sitio oficial
  • Objective-C: Core Data (Parte de la API de Cocoa), proporciona la capacidad de persistencia mediante serialización para dispositivos con Mac OSX o iOS, más información en la guía de programación de Core Data
  • PHP: Doctrine, mencionado anteriormente, un proyecto independiente, con la especialidad de que posee su propio lenguaje para el acceso a datos, llamado Doctrine Query Language. Más información en el sitio oficial
  • Ruby: ActiveRecord (Parte de Ruby On Rails), genera un modelo de persistencia basado en las clases, proporciona acceso a datos en el framework y es la clase base para los modelos del mismo. En la API de Rails se puede ver el sistema en detalle.

Conclusiones

Los modelos ORM proporcionan grandes ventajas a proyectos que empiezan, ya que permiten tener acceso a los datos de una manera sencilla y rápida, además de proporcionar cierta abstracción sobre la base de datos que se encuentra por debajo.

Es cierto que no es la única manera de acceder a los datos, ya que soluciones específicas habitualmente tendrán mejor rendimiento, ya que no se hace una transformación de las ordenes y de los datos.

Finalmente creo que se deben conocer, y tenerlos como alternativa o como sistema principal. Como siempre, todo depende del uso.

Half ToDo: Un caso de uso de ASP.net MVC4

Página principal

He de reconocer que me gustan los gestores de tareas, me imagino que será por lo mal que gestiono yo las mías. He probado muchos de los disponibles en el mercado y además quería hacer mi propia solución. Han sido varios intentos (MVCTask usando Azure, MetroTask para Windows 8, otro cliente por línea de comandos), pero creo que esta es la buena.

Las bases

La idea para desarrollar la aplicación era la siguiente:

  • Debía de ser simple
  • Debía de ser visualmente atractiva
  • Debía de resolver un problema

La idea era simple: Una práctica está dividida en varias tareas, y las tareas pueden tener dos estados, completada y sin completar. El porcentaje de terminación de una práctica está definido por el cociente entre las prácticas completadas dividido entre las prácticas totales.

Además, cada práctica estará enlazada a una persona concreta, de tal manera que yo solamente tenga acceso a las mías y no a las del resto de la gente (por aquello de la seguridad y tal).

Bajo el capó

Con esas tres premisas abrí Visual Studio y empecé un proyecto de nombre PracticasManager, ya que en un principio el proyecto va destinado a gestión de prácticas en la universidad.

Para realizar el proyecto me basé en la última versión de ASP.net MVC, la 4 que se encuentra en estos momentos en su fase de Developer Preview, ya que quería probar ciertas capacidades relativas al uso como aplicación móvil. El lenguaje de programación es C# y la interfaz para la creación de la aplicación es Razor.

El sistema ORM para el mapeo desde los objetos hasta la base de datos no podía ser otro que Entity Framework, usando el método Code-First, que permite definir nuestros objetos usando POCO (Plain Old C# object) y que las tablas de la base de datos se generen automáticamente.

La base de datos está gestionada por un SQL Server 2008 R2 que proporciona el proveedor del alojamiento.

Una cara bonita

Para la interfaz gráfica he usado Twitter Bootstrap, un conjunto de plantillas CSS y Javascript que permiten a los desarrolladores que no sabemos combinar colores que salga una interfaz decente. Finalmente la barra de progreso está creada con JQuery UI.

Detalle del listado de las tareas

También para móviles

Otra de las cosas que quería probar era el comportamiento de la aplicación en un móvil, así que usando las nuevas características de ASP.net MVC4, jQuery Mobile (y algun que otro paquete de nuget), pude implementar una interfaz básica de la aplicación para dispositivos móviles.

Detalle de la interfaz para dispositivos móviles

Alojamiento

Para el alojamiento decidí buscar algo diferente, tras probar Azure para otros proyectos (muy potente, y muy escalable, pero muy complejo para las necesidades de este proyecto) descubrí AppHarbor, un sistema de despliegue en la nube basado en Git (como Heroku, el sistema de despliegue preferido de las aplicaciones Ruby on Rails), completamente gratuito (para proyectos pequeños) y muy fácil de usar. La experiencia ha sido muy gratificante y recomiendo probarlo aunque sea con proyectos muy pequeños.

Detalle de interfaz de administración de AppHarbor

Conclusiones

Este proyecto me ha servido para poder lanzar una solución funcional para un problema concreto, así como la ocasión de probar tecnologías que no había visto hasta ahora, como JQuery Mobile, Bootstrap, el despliegue en AppHarbor entre otros.

Te animo a que la pruebes, está en una fase bastante experimental, así que puedes encontrar algún que otro fallo. Tanto si te gusta como si no, dejame un comentario y sabré qué puedo mejorar.

Enlace: Half todo en AppHarbor