4. Caso práctico con MySQL 5.5.28
4.1. Instalación de las herramientas
Las herramientas que hay que instalar son las siguientes:
- el SGBD: [http://dev.mysql.com/downloads/];
- una herramienta de administración: EMS, SQL Manager para MySQL, Freeware [http://www.sqlmanager.net/fr/products/mysql/manager/download].
En los ejemplos siguientes, el usuario root tiene la contraseña root.
Iniciemos MySQL5. En este caso, 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 vamos a administrar 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 va a 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] que se muestra a continuación:
![]() |
- en [2], añadimos referencias al proyecto a través de NuGet;
![]() |
- en [3], se añade la referencia EF 5;
- en [4], ya figura entre las referencias;
![]() |
- en [5], volvemos a empezar para añadir esta vez [MySQL.Data.Entities], que es un conector ADO.NET para Entity Framework. Para encontrar el paquete, podemos utilizar 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 vamos a modificar 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. Este puede variar en función de SGBD. Este es el caso aquí, donde no habrá ningún esquema. El archivo [Entites.cs] queda 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 recuerda al campo con la anotación [Timestamp] en las entidades:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Decidimos sustituir estas tres líneas por las siguientes:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
Cambiamos el tipo de la columna, que pasa 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 sustituimos por la anotación [ConcurrencyCheck]. Ambas anotaciones gestionan el acceso concurrente. Hacemos esto para las cuatro entidades y, a continuación, volvemos a ejecutar la aplicación. A continuación, aparece el siguiente error:
La línea 1 indica un error de sintaxis en el SQL ejecutado por MySQL. Dado que este no lo hemos generado nosotros, sino que lo ha generado el proveedor ADO.NET de MySQL, no podemos corregir este punto. No obstante, se puede observar que se han creado las siguientes tablas en [1]:
![]() |
- En [2] se aprecia la estructura de la tabla [clients] [3].
Hay que realizar varias modificaciones en la base generada:
- el tipo de la columna [VERSIONING] no es adecuado. Hay que asignarle el tipo MySQL [TIMESTAMP];
- recordemos que la tabla [rvs] tiene una restricción de unicidad. No se ha creado 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 de creación de 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 «clients»:
#
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 han sido 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 foránea 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 foránea 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 de generación de 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. Ofrecen los mismos resultados que con SQL Server, salvo el programa [ModifyDetachedEntities], que se cuelga. Para entender por qué, podemos fijarnos en el resultado del programa [ModifyAtttachedEntities]:
- líneas 1-2: un cliente antes de guardar el contexto;
- líneas 3-4: el cliente tras el guardado. Tiene una clave primaria, pero no hay ningún valor para su campo [Versioning], mientras que SQL Server actualizaba el campo [Timestamp] de la entidad.
Ahora examinemos el código del programa [ModifyDetachedEntities] que da error:
using System;
...
namespace RdvMedecins_01
{
class ModifyDetachedEntities
{
static void Main(string[] args)
{
Client client1;
// Se vacía la base de datos actual
Erase();
// Se añade un cliente
using (var context = new RdvMedecinsContext())
{
// Creación de un cliente
client1 = new Client { Titre = "x", Nom = "x", Prenom = "x" };
// Añadir el 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 «cliente1» en el contexto en 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». Fallan porque no tiene la versión que hay en la base de datos.
El problema se resuelve insertando el siguiente código entre las líneas 25 y 26:
// se recupera «client1» para obtener su versión
using (var context = new RdvMedecinsContext())
{
// «client2» estará en el contexto
Client client2 = context.Clients.Find(client1.Id);
// se establece la versión de «cliente1» en la de «cliente2»
client1.Versioning = client2.Versioning;
}
A partir de ahora, la entidad [client1] tiene la misma versión que en la base de datos y, por lo tanto, puede utilizarse para actualizar la línea de la base de datos.
4.3. Arquitectura multicapa basada en EF 5
Volvemos a nuestro caso práctico descrito en el apartado 2.
![]() |
Comenzaremos por crear la capa de acceso a datos [DAO]. Para ello, creamos el proyecto de consola VS 2012 [RdvMedecins-MySQL-02] [1]:
![]() |
- en [2], se añaden 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 sustituye 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 gestionados 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 es ahora [RdvMedecins-MySQL-02].
Una vez hecho esto, estamos listos para ejecutar la prueba de la capa [DAO]. Antes hay que asegurarse de rellenar la base de datos (programa [Fill] del proyecto [RdvMedecins-MySQL-01]). La prueba se realiza con éxito.
Creamos el archivo DLL del proyecto tal y como se hizo para el proyecto [RdvMedecins-SqlServer-02] y reunimos eltodos los archivos DLL del proyecto en una carpeta [lib] creada en [RdvMedecins-MySQL-02]. Estas serán las referencias del proyecto web [RdvMedecins-MySQL-03] que vendrá a continuación.
![]() |
Ya estamos listos para crear 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;
- por [6], para sustituirlas 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]. Sustituimos 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 ha modificado el campo que se utilizaba para gestionar la concurrencia en el 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 han modificado las anotaciones [Table] que vinculan una entidad a 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 ha requerido modificar el código.
Al final, se trata de modificaciones bastante menores, pero aun así fue necesario revisar el código. Repetimos el mismo proceso para otros tres SGBD:
- El SGBD Oracle Database Express Edition 11g Release 2;
- El SGBD PostgreSQL 9.2.1;
- SGBD Firebird 2.1.
















