4. Приклад використання з MySQL 5.5.28
4.1. Встановлення інструментів
Необхідно встановити такі інструменти:
- SGBD: [http://dev.mysql.com/downloads/];
- інструмент адміністрування: EMS, SQL Manager для MySQL, безкоштовне програмне забезпечення [http://www.sqlmanager.net/fr/products/mysql/manager/download].
У наведених нижче прикладах користувач root має пароль root.
Запустимо MySQL5. Тут ми робимо це з вікна служб Windows [1]. У [2] запускається SGBD.
![]() |
Тепер запускаємо інструмент [SQL Manager Lite for MySQL], за допомогою якого будемо керувати SGBD та [3].
![]() |
- У [4] ми створюємо нову базу даних;
- у [5] вказуємо назву бази даних;
![]() |
- у [5], входимо як root / root;
- у [6] підтверджуємо команду SQL, яка буде виконана;
![]() |
- у [7] база даних створена. Тепер її потрібно зареєструвати в [EMS Manager]. Інформація правильна. Виконуємо [OK];
- у [8] ми входимо в систему;
- у [9] [EMS Manager] відображає базу даних, яка наразі порожня.
Тепер ми підключимо до цієї бази даних проект VS 2012.
4.2. Створення бази даних на основі об’єктів
Створюємо консольний проєкт VS 2012 [RdvMedecins-MySQL-01] [1], як показано нижче:
![]() |
- у [2] додаємо посилання на проект через NuGet;
![]() |
- у [3] додається посилання EF 5;
- у [4] вона тепер є серед посилань;
![]() |
- у [5] повторюємо процедуру, щоб цього разу додати [MySQL.Data.Entities], який є коннектором ADO.NET для Entity Framework. Щоб знайти пакет, можна скористатися полем пошуку [6];
- у [7] з’являються два посилання: [MySQL.Data.Entities] та [MySQL.Data], причому останнє є залежністю від першого.
Тепер ми створимо проект [RdvMedecins-MySQL-01] на основі проекту [RdvMedecins-SqlServer-01].
![]() |
- у [1] скопіюємо вибрані елементи;
- у [2] вставляємо їх у проект [RdvMedecins-MySQL-01];
- у [3], оскільки існує кілька програм із методом [Main], нам потрібно вказати проект, з якого слід розпочати роботу.
На цьому етапі створення проекту має відбутися успішно. Тепер ми змінимо файл конфігурації [App.config], який налаштовує рядок підключення до бази даних, та файл DbProviderFactory. Він набуває такого вигляду:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- Докладнішу інформацію про налаштування Entity Framework можна знайти на сайті 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>
<!-- ланцюг з'єднання-->
<connectionStrings>
<add name="monContexte"
connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<!-- фабричний провайдер -->
<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>
- рядок 17: рядок підключення до бази даних MySQL [rdvmedecins-ef], який ми створили;
- рядок 24: версія повинна відповідати версії посилання [MySql.Data] у проєкті [1]:
![]() |
У файлі [Entites.cs] також міститься деяка конфігурація, де вказуються назви таблиць та схема, до якої вони належать. Це може змінюватися залежно від SGBD. Так відбувається в даному випадку, де схеми не буде. Файл [Entites.cs] виглядає наступним чином:
[Table("MEDECINS")]
public class Medecin : Personne
{...}
[Table("CLIENTS")]
public class Client : Personne
{...}
[Table("CRENEAUX")]
public class Creneau
{...}
[Table("RVS")]
public class Rv
{...}
Запустимо програму [CreateDB_01] [2]. Отримуємо таке виключення:
Ця сама помилка з’являється чотири рази (рядки 2–5). Тип rowversion нагадує поле з анотацією [Timestamp] у сутностях:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Ми вирішили замінити ці три рядки на такі:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
Змінюємо тип стовпця з byte[] на DateTime?. Ми робимо це тому, що MySQL має тип [TIMESTAMP], який представляє дату/час, і стовпець із цим типом автоматично оновлюється на MySQL щоразу, коли оновлюється рядок. Це дозволить нам керувати паралельним доступом.
Анотація [Timestamp] може застосовуватися лише до стовпця типу byte[]. Ми замінюємо її на анотацію [ConcurrencyCheck]. Обидві ці анотації забезпечують управління паралельним доступом. Ми робимо це для всіх чотирьох сутностей, а потім запускаємо додаток знову. Після цього ми отримуємо таку помилку:
У рядку 1 вказано синтаксичну помилку в анотації SQL, яка виконується анотацією MySQL. Оскільки ця програма була згенерована не нами, а провайдером ADO.NET з MySQL, ми не можемо виправити цю помилку. Проте можна помітити, що були створені таблиці [1], наведені нижче:
![]() |
- у [2] видно структуру таблиці [clients] [3].
У створеній базі даних потрібно внести кілька змін:
- тип стовпця [VERSIONING] не підходить. Йому потрібно присвоїти тип MySQL [TIMESTAMP];
- слід пам’ятати, що таблиця [rvs] має обмеження унікальності. Вона не була створена під час цього генерування;
- з’єднувач ADO.NET з SQL Server згенерував зовнішні ключі з умовою ON DELETE CASCADE. Коннектор ADO.NET сервера MySQL цього не зробив.
Як і у випадку з сервером SQL, нам потрібно змінити згенеровану базу даних. Ми не показуємо, як саме внести ці зміни. Ми просто наводимо скрипт для створення бази даних:
# SQL Manager Lite для MySQL 5.3.0.2
# ---------------------------------------
# Хост : localhost
# Порт : 3306
# База даних : 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`;
#
# Структура таблиці `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=''
;
#
# Структура таблиці `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=''
;
#
# Структура таблиці `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=''
;
#
# Структура таблиці `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=''
;
- рядки 22, 38, 54, 74: первинні ключі ID таблиць мають тип AUTO_INCREMENT, отже, згенеровані MySQL;
- рядки 26, 42, 60, 78: стовпець VERSIONING має тип TIMESTAMP і оновлюється під час виконання INSERT або UPDATE;
- рядок 63: зовнішній ключ таблиці [creneaux] до таблиці [medecins] із умовою ON DELETE CASCADE;
- рядок 80: обмеження унікальності таблиці [rvs];
- рядок 83: чужорідний ключ таблиці [rvs] до таблиці [creneaux] із клаузулою ON DELETE CASCADE;
- рядок 84: чужий ключ з таблиці [rvs] до таблиці [clients] із умовою ON DELETE CASCADE;
Скрипт для генерації таблиць бази даних MySQL [rvmedecins-ef] розміщено у папці [RdvMedecins / databases / mysql]. Користувач може завантажити та виконати його для створення своїх таблиць.
Після цього можна запускати різні програми проекту. Вони дають ті самі результати, що й із сервером SQL, за винятком програми [ModifyDetachedEntities], яка вилітає. Щоб зрозуміти, чому так відбувається, можна подивитися на результат роботи програми [ModifyAtttachedEntities]:
- рядки 1–2: клієнт перед збереженням контексту;
- рядки 3–4: клієнт після збереження. Він має первинний ключ, але не має значення для свого поля [Versioning], тоді як SQL Server оновлював поле [Timestamp] сутності.
Тепер розглянемо код програми [ModifyDetachedEntities], яка дає збій:
using System;
...
namespace RdvMedecins_01
{
class ModifyDetachedEntities
{
static void Main(string[] args)
{
Client client1;
// очищення поточної бази даних
Erase();
// додаємо клієнта
using (var context = new RdvMedecinsContext())
{
// Створення клієнта
client1 = new Client { Titre = "x", Nom = "x", Prenom = "x" };
// додавання клієнта до контексту
context.Clients.Add(client1);
// збереження контексту
context.SaveChanges();
}
// відображення бази
Dump("1-----------------------------");
// клієнт1 відсутній у контексті — його змінюють
client1.Nom = "y";
// зміна об’єкта поза контекстом
using (var context = new RdvMedecinsContext())
{
// тут ми маємо новий порожній контекст
// клієнт1 додано до контексту у зміненому стані
context.Entry(client1).State = EntityState.Modified;
// зберігаємо контекст
context.SaveChanges();
}
...
}
static void Erase()
{
...
}
static void Dump(string str)
{
...
}
}
}
- рядок 20: клієнт зберігається. Він має свій первинний ключ, але за своєю версією;
- рядок 33: виконується зміна з client1. Вона завершується з помилкою, оскільки у нього немає тієї версії, яка є в базі.
Проблему можна вирішити, вставивши наступний код між рядками 25 і 26:
// отримуємо «client1», щоб дізнатися його версію
using (var context = new RdvMedecinsContext())
{
// «client2» буде в контексті
Client client2 = context.Clients.Find(client1.Id);
// версію клієнта1 встановлюємо на версію клієнта2
client1.Versioning = client2.Versioning;
}
Відтепер суть [client1] має ту саму версію, що й у базі даних, і тому її можна використовувати для оновлення рядка в базі даних.
4.3. Багаторівнева архітектура на основі EF 5
Повернемося до нашого прикладу, описаного в параграфі 2.
![]() |
Почнемо з побудови шару [DAO] для доступу до даних. Для цього створюємо консольний проєкт VS 2012 [RdvMedecins-MySQL-02] [1]:
![]() |
- у [2] додаються посилання [Common.Logging, EntityFramework, MySql.Data, MySql.Data.Entity, Spring.Core] разом із NuGet;
- у [3] папка [Models] копіюється з проєкту [RdvMedecins-MySQL-01];
![]() |
- у [4] папки [Dao, Exception, Tests] та файл [App.config] скопійовано з проєкту [RdvMedecins-SqlServer-02];
- у [5] файл [Program.cs] було видалено;
- у [6] проект налаштовано на виконання тестової програми шару [DAO].
У файлі [App.config] дані бази SQL Server замінюються даними бази MySQL. Їх можна знайти у файлі [App.config] проекту [RdvMedecins-MySQL-01]:
<!-- ланцюг з'єднання-->
<connectionStrings>
<add name="monContexte"
connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<!-- фабрика провайдера -->
<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>
Об’єкти, що керуються Spring, також змінюються. Наразі маємо:
<!-- конфігурація 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>
У рядку 7 вказано збірку проекту [RdvMedecins-SqlServer-02]. Тепер збірка має назву [RdvMedecins-MySQL-02].
Після цього ми готові виконати тест шару [DAO]. Перед цим необхідно подбати про заповнення бази даних (програма [Fill] проекту [RdvMedecins-MySQL-01]). Тестова програма проходить успішно.
Ми створюємо DLL для цього проєкту так само, як це було зроблено для проєкту [RdvMedecins-SqlServer-02], і збираємоусі файли DLL цього проєкту в папку [lib], створену в [RdvMedecins-MySQL-02]. Це будуть посилання для наступного веб-проєкту [RdvMedecins-MySQL-03].
![]() |
Тепер ми готові до створення шару [ASP.NET] нашого додатка:
![]() |
Ми почнемо з проєкту [RdvMedecins-SqlServer-03]. Скопіюємо папку цього проєкту в [RdvMedecins-MySQL-03] та [1]:
![]() |
- у [2], за допомогою VS 2012 Express для веб, ми відкриваємо рішення з папки [RdvMedecins-MySQL-03];
- у [3] ми змінюємо як назву рішення, так і назву проєкту;
![]() |
- у [4] — поточні посилання проекту;
- у [5] видаляємо їх;
- на [6], щоб замінити їх посиланнями на DLL, які ми щойно зберегли у папці [lib] проекту [RdvMedecins-MySQL-02].
Залишилося лише змінити файл [Web.config]. Замінюємо його поточний вміст на вміст файлу [App.config] з проєкту [RdvMedecins-MySQL-02]. Зробивши це, запускаємо веб-проєкт. Він працює.
4.4. Conclusion
Підсумуємо, що було зроблено для переходу від сервера SGBD SQL до SGBD MySQL:
- було змінено поле, яке використовувалося для управління конкуренцією доступу до об’єктів. Його версія на сервері SQL була такою:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Тепер вона виглядає так:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
разом із MySQL;
- анотації [Table], що пов’язують суть із таблицею, було змінено;
- рядок підключення до бази даних та [DbProviderFactory] було змінено у файлах конфігурації [App.config] та [Web.config];
- після збереження в базі даних суть SQL Server мала одночасно і первинний ключ, і Timestamp. З MySQL вона мала лише первинний ключ. Це призвело до зміни коду.
У підсумку змін було небагато, але все ж довелося переглянути код. Ми повторюємо ту саму процедуру для трьох інших SGBD:
- SGBD — Oracle Database Express Edition 11g Release 2;
- SGBD PostgreSQL 9.2.1;
- SGBD Firebird 2.1.
















