4. Caso práctico con MySQL 5.5.28
4.1. Instalación de las herramientas
Las herramientas que se deben instalar son las siguientes:
- el SGBD: [http://dev.mysql.com/downloads/];
- una herramienta de administración: EMS, SQL Manager para MySQL, y el software gratuito [http://www.sqlmanager.net/fr/products/mysql/manager/download].
En los siguientes ejemplos, el usuario root tiene la contraseña root.
Iniciemos MySQL5. Aquí lo hacemos desde la ventana de servicios de Windows [1]. En [2], se inicia SGBD.
![]() |
Ahora iniciamos la herramienta [SQL Manager Lite for MySQL], con la que administraremos el SGBD y el [3].
![]() |
- En [4], creamos una nueva base de datos;
- en [5], indicamos el nombre de la base de datos;
![]() |
- en [5], nos conectamos como root / root;
- en [6], validamos el comando SQL que se ejecutará;
![]() |
- en [7], se ha creado la base de datos. Ahora debe registrarse en [EMS Manager]. La información es correcta. Se ejecuta [OK];
- en [8], nos conectamos a ella;
- en [9], [EMS Manager] muestra la base de datos, que por el momento está vacía.
Ahora vamos a conectar un proyecto VS 2012 a esta base de datos.
4.2. Creación de la base a partir de las entidades
Creamos el proyecto de consola VS 2012 [RdvMedecins-MySQL-01] [1] a continuación:
![]() |
- en [2], agregamos referencias al proyecto a través de NuGet;
![]() |
- en [3], se agrega la referencia EF 5;
- en [4], ahora aparece en las referencias;
![]() |
- en [5], volvemos a empezar para agregar esta vez [MySQL.Data.Entities], que es un conector ADO.NET para Entity Framework. Para encontrar el paquete, podemos usar el cuadro de búsqueda de [6];
- en [7], aparecen dos referencias: [MySQL.Data.Entities] y [MySQL.Data], siendo la última una dependencia de la primera.
Ahora vamos a compilar el proyecto [RdvMedecins-MySQL-01] a partir del proyecto [RdvMedecins-SqlServer-01].
![]() |
- en [1], copiamos los elementos seleccionados;
- en [2], los pegamos en el proyecto [RdvMedecins-MySQL-01];
- en [3], dado que hay varios programas con el método [Main], debemos especificar el proyecto de inicio.
En este punto, la generación del proyecto debería completarse con éxito. Ahora modificaremos el archivo de configuración [App.config], que configura la cadena de conexión a la base de datos, y el DbProviderFactory. Quedará así:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- Para obtener más información sobre la configuración de Entity Framework, visita http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
</entityFramework>
<!-- cadena de conexión-->
<connectionStrings>
<add name="monContexte"
connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<!-- el proveedor de fábrica -->
<system.data>
<DbProviderFactories>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL"
type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"
/>
</DbProviderFactories>
</system.data>
</configuration>
- línea 17: la cadena de conexión a la base de datos MySQL [rdvmedecins-ef] que hemos creado;
- línea 24: la versión debe coincidir con la de la referencia [MySql.Data] del proyecto [1]:
![]() |
También hay algunos ajustes de configuración en el archivo [Entites.cs], donde se especifican los nombres de las tablas y el esquema al que pertenecen. Esto puede variar según el SGBD. Este es el caso aquí, donde no habrá ningún esquema. El archivo [Entites.cs] se modifica de la siguiente manera:
[Table("MEDECINS")]
public class Medecin : Personne
{...}
[Table("CLIENTS")]
public class Client : Personne
{...}
[Table("CRENEAUX")]
public class Creneau
{...}
[Table("RVS")]
public class Rv
{...}
Ejecutemos el programa [CreateDB_01] [2]. Se produce la siguiente excepción:
El mismo error aparece cuatro veces (líneas 2-5). El tipo rowversion se asemeja al campo con la anotación [Timestamp] en las entidades:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Decidimos reemplazar estas tres líneas por las siguientes:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
Cambiamos el tipo de la columna de byte[] a DateTime?. Hacemos esto porque MySQL tiene un tipo [TIMESTAMP] que representa una fecha y hora, y una columna con este tipo se actualiza automáticamente con MySQL cada vez que se actualiza la fila. Esto nos permitirá gestionar los accesos concurrentes.
La anotación [Timestamp] solo se puede aplicar a una columna de tipo byte[]. La reemplazamos por la anotación [ConcurrencyCheck]. Ambas anotaciones gestionan el acceso concurrente. Hacemos esto para las cuatro entidades y luego volvemos a ejecutar la aplicación. Entonces obtenemos el siguiente error:
La línea 1 indica un error de sintaxis en el SQL ejecutado por MySQL. Dado que este no fue generado por nosotros, sino por el proveedor ADO.NET de MySQL, no podemos corregir este punto. Sin embargo, se puede observar que se han creado las siguientes tablas en [1]:
![]() |
- En [2], se observa la estructura de la tabla [clients] [3].
Hay varias modificaciones que se deben realizar en la base generada:
- el tipo de la columna [VERSIONING] no es adecuado. Se le debe asignar el tipo MySQL [TIMESTAMP];
- recordemos que la tabla [rvs] tiene una restricción de unicidad. No se creó en esta generación;
- el conector ADO.NET de SQL Server había generado claves externas con la cláusula ON DELETE CASCADE. El conector ADO.NET de MySQL no lo hizo.
Al igual que hicimos con el servidor SQL, debemos modificar la base de datos generada. No mostramos cómo realizar las modificaciones. Simplemente proporcionamos el script para crear la base de datos:
# SQL Manager Lite para MySQL 5.3.0.2
# ---------------------------------------
# Host : localhost
# Puerto: 3306
# Base de datos: rdvmedecins-ef
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
SET FOREIGN_KEY_CHECKS=0;
USE `rdvmedecins-ef`;
#
# Estructura de la tabla `clientes`:
#
CREATE TABLE `clients` (
`ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRENOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`TITRE` VARCHAR(5) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY USING BTREE (`ID`) COMMENT ''
)ENGINE=InnoDB
AUTO_INCREMENT=96 AVG_ROW_LENGTH=4096 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
#
# Estructura de la tabla `medecins`:
#
CREATE TABLE `medecins` (
`ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRENOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`TITRE` VARCHAR(5) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY USING BTREE (`ID`) COMMENT ''
)ENGINE=InnoDB
AUTO_INCREMENT=56 AVG_ROW_LENGTH=4096 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
#
# Estructura de la tabla `creneaux`:
#
CREATE TABLE `creneaux` (
`ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
`HDEBUT` INTEGER(11) NOT NULL,
`MDEBUT` INTEGER(11) NOT NULL,
`HFIN` INTEGER(11) NOT NULL,
`MFIN` INTEGER(11) NOT NULL,
`MEDECIN_ID` INTEGER(11) NOT NULL,
`VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY USING BTREE (`ID`) COMMENT '',
INDEX `MEDECIN_ID` USING BTREE (`MEDECIN_ID`) COMMENT '',
CONSTRAINT `creneaux_ibfk_1` FOREIGN KEY (`MEDECIN_ID`) REFERENCES `medecins` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION
)ENGINE=InnoDB
AUTO_INCREMENT=472 AVG_ROW_LENGTH=455 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
#
# Estructura de la tabla `rvs`:
#
CREATE TABLE `rvs` (
`ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
`JOUR` DATE NOT NULL,
`CRENEAU_ID` INTEGER(11) NOT NULL,
`CLIENT_ID` INTEGER(11) NOT NULL,
`VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY USING BTREE (`ID`) COMMENT '',
UNIQUE INDEX `CRENEAU_ID_JOUR` USING BTREE (`JOUR`, `CRENEAU_ID`) COMMENT '',
INDEX `CRENEAU_ID` USING BTREE (`CRENEAU_ID`) COMMENT '',
INDEX `CLIENT_ID` USING BTREE (`CLIENT_ID`) COMMENT '',
CONSTRAINT `rvs_ibfk_2` FOREIGN KEY (`CLIENT_ID`) REFERENCES `clients` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `rvs_ibfk_1` FOREIGN KEY (`CRENEAU_ID`) REFERENCES `creneaux` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION
)ENGINE=InnoDB
AUTO_INCREMENT=28 AVG_ROW_LENGTH=16384 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
- líneas 22, 38, 54, 74: las claves primarias ID de las tablas son de tipo AUTO_INCREMENT, por lo que fueron generadas por MySQL;
- líneas 26, 42, 60, 78: la columna VERSIONING es de tipo TIMESTAMP y se actualiza durante un INSERT o un UPDATE;
- línea 63: la clave externa de la tabla [creneaux] hacia la tabla [medecins] con la cláusula ON DELETE CASCADE;
- línea 80: la restricción de unicidad de la tabla [rvs];
- línea 83: la clave externa de la tabla [rvs] hacia la tabla [creneaux] con la cláusula ON DELETE CASCADE;
- línea 84: la clave externa de la tabla [rvs] a la tabla [clients] con la cláusula ON DELETE CASCADE;
El script para generar las tablas de la base de datos MySQL [rvmedecins-ef] se ha colocado en la carpeta [RdvMedecins / databases / mysql]. El lector podrá cargarlo y ejecutarlo para crear sus tablas.
Una vez hecho esto, se pueden ejecutar los distintos programas del proyecto. Estos arrojan los mismos resultados que con SQL Server, excepto el programa [ModifyDetachedEntities], que se cuelga. Para entender por qué, podemos observar el resultado del programa [ModifyAtttachedEntities]:
- líneas 1-2: un cliente antes de guardar el contexto;
- líneas 3-4: el cliente después de la copia de seguridad. Tiene una clave primaria, pero no tiene valor para su campo [Versioning], mientras que SQL Server actualizaba el campo [Timestamp] de la entidad.
Ahora analicemos el código del programa [ModifyDetachedEntities] que falla:
using System;
...
namespace RdvMedecins_01
{
class ModifyDetachedEntities
{
static void Main(string[] args)
{
Client client1;
// se vacía la base de datos actual
Erase();
// se agrega un cliente
using (var context = new RdvMedecinsContext())
{
// creación de cliente
client1 = new Client { Titre = "x", Nom = "x", Prenom = "x" };
// Agregación del cliente al contexto
context.Clients.Add(client1);
// se guarda el contexto
context.SaveChanges();
}
// visualización básica
Dump("1-----------------------------");
// El cliente 1 no está en el contexto; se modifica
client1.Nom = "y";
// modificación de entidad fuera del contexto
using (var context = new RdvMedecinsContext())
{
// aquí tenemos un nuevo contexto vacío
// se coloca al cliente 1 en el contexto en un estado modificado
context.Entry(client1).State = EntityState.Modified;
// se guarda el contexto
context.SaveChanges();
}
...
}
static void Erase()
{
...
}
static void Dump(string str)
{
...
}
}
}
- línea 20: se guarda un cliente. En ese momento tiene su clave primaria, pero según su versión;
- línea 33: se realiza una modificación con «cliente1». Esta falla porque no tiene la versión que está en la base de datos.
Resolvemos el problema insertando el siguiente código entre las líneas 25 y 26:
// se recupera «cliente1» para obtener su versión
using (var context = new RdvMedecinsContext())
{
// «cliente2» estará en el contexto
Client client2 = context.Clients.Find(client1.Id);
// se establece la versión de «cliente1» igual a la de «cliente2»
client1.Versioning = client2.Versioning;
}
Ahora, la entidad [client1] tiene la misma versión que en la base de datos y, por lo tanto, puede utilizarse para actualizar la fila en la base de datos.
4.3. Arquitectura multicapa basada en EF 5
Volvemos a nuestro caso de estudio descrito en el párrafo 2.
![]() |
Comenzaremos por construir la capa de acceso a datos [DAO]. Para ello, creamos el proyecto de consola VS 2012 [RdvMedecins-MySQL-02] [1]:
![]() |
- en [2], se agregan las referencias [Common.Logging, EntityFramework, MySql.Data, MySql.Data.Entity, Spring.Core] junto con NuGet;
- en [3], se copia la carpeta [Models] del proyecto [RdvMedecins-MySQL-01];
![]() |
- en [4], se copian las carpetas [Dao, Exception, Tests] y el archivo [App.config] del proyecto [RdvMedecins-SqlServer-02];
- en [5], se ha eliminado el archivo [Program.cs];
- en [6], el proyecto está configurado para ejecutar el programa de prueba de la capa [DAO].
En el archivo [App.config], se reemplaza la información de la base de datos SQL Server por la de la base de datos MySQL. Esta información se encuentra en el archivo [App.config] del proyecto [RdvMedecins-MySQL-01]:
<!-- cadena de conexión-->
<connectionStrings>
<add name="monContexte"
connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<!-- el proveedor de fábrica -->
<system.data>
<DbProviderFactories>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL"
type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"
/>
</DbProviderFactories>
</system.data>
Los objetos administrados por Spring también cambian. Actualmente tenemos:
<!-- configuración de Spring -->
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object id="rdvmedecinsDao" type="RdvMedecins.Dao.Dao,RdvMedecins-SqlServer-02" />
</objects>
</spring>
La línea 7 hace referencia al ensamblado del proyecto [RdvMedecins-SqlServer-02]. El ensamblado ahora es [RdvMedecins-MySQL-02].
Una vez hecho esto, estamos listos para ejecutar la prueba de la capa [DAO]. Antes hay que asegurarse de llenar la base de datos (programa [Fill] del proyecto [RdvMedecins-MySQL-01]). La prueba se ejecuta con éxito.
Creamos el DLL del proyecto tal como se hizo para el proyecto [RdvMedecins-SqlServer-02] y reunimos eltodos los archivos DLL del proyecto en una carpeta [lib] creada dentro de [RdvMedecins-MySQL-02]. Estas serán las referencias del proyecto web [RdvMedecins-MySQL-03] que se presentará a continuación.
![]() |
Ahora estamos listos para construir la capa [ASP.NET] de nuestra aplicación:
![]() |
Partiremos del proyecto [RdvMedecins-SqlServer-03]. Duplicamos la carpeta de este proyecto en [RdvMedecins-MySQL-03] y [1]:
![]() |
- en [2], con VS 2012 Express para la web, abrimos la solución de la carpeta [RdvMedecins-MySQL-03];
- en [3], cambiamos tanto el nombre de la solución como el del proyecto;
![]() |
- en [4], las referencias actuales del proyecto;
- en [5], las eliminamos;
- a [6], para reemplazarlas por referencias a DLL, que acabamos de guardar en una carpeta [lib] del proyecto [RdvMedecins-MySQL-02].
Ahora solo nos queda modificar el archivo [Web.config]. Reemplazamos su contenido actual por el contenido del archivo [App.config] del proyecto [RdvMedecins-MySQL-02]. Una vez hecho esto, ejecutamos el proyecto web. Funciona.
4.4. Conclusion
Resumamos lo que se ha hecho para pasar del servidor SGBD SQL al SGBD MySQL:
- se modificó el campo que se utilizaba para gestionar la concurrencia de acceso a las entidades. Su versión en el servidor SQL era:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Ahora es:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
junto con MySQL;
- se modificaron las anotaciones [Table] que vinculan una entidad con una tabla;
- se han modificado la cadena de conexión a la base de datos y el [DbProviderFactory] en los archivos de configuración [App.config] y [Web.config];
- tras guardar en la base de datos, una entidad SQL Server tenía tanto su clave primaria como su Timestamp. Con MySQL, solo tenía su clave primaria. Esto requirió la modificación de un código.
Al final, fueron pocos cambios, pero de todos modos hubo que revisar el código. Repetimos el mismo proceso para otros tres SGBD:
- El SGBD Oracle Database Express Edition 11g Versión 2;
- El SGBD PostgreSQL 9.2.1;
- SGBD Firebird 2.1.
















