4. مطالعه موردی با MySQL 5.5.28
4.1. نصب ابزارها
ابزارهای قابل نصب به شرح زیر هستند:
- SGBD: [http://dev.mysql.com/downloads/];
- یک ابزار مدیریتی: EMS، SQL مدیر برای MySQL، نرمافزار رایگان [http://www.sqlmanager.net/fr/products/mysql/manager/download].
در مثالهای زیر، کاربر ریشه رمز عبور 'root' را دارد.
بیایید MySQL5 را راهاندازی کنیم. در اینجا این کار را از پنجرهٔ سرویسهای ویندوز [1] انجام میدهیم. در [2]، SGBD راهاندازی میشود.
![]() |
اکنون ابزار [SQL Manager Lite for MySQL] را راهاندازی میکنیم که از آن برای مدیریت SGBD و [3] استفاده خواهیم کرد.
![]() |
- در [4]، یک پایگاه داده جدید ایجاد میکنیم؛
- در [5]، نام پایگاه داده را مشخص میکنیم؛
![]() |
- در [5]، ما با حساب ریشه / ریشه وارد میشویم؛
- در [6]، ما فرمان SQL را که قرار است اجرا شود، تأیید میکنیم؛
![]() |
- در [7]، پایگاه داده ایجاد شده است. اکنون باید در [EMS Manager] ذخیره شود. اطلاعات صحیح است. [OK] را اجرا کنید؛
- در [8]، ما وارد میشویم؛
- در [9]، [EMS Manager] پایگاه داده را نمایش میدهد که در حال حاضر خالی است.
اکنون یک پروژه VS مربوط به سال ۲۰۱۲ را به این پایگاه داده متصل خواهیم کرد.
4.2. ایجاد پایگاه داده از طریق اِنتِیتیها
ما پروژه کنسول VS 2012 [RdvMedecins-MySQL-01] [1] را همانطور که در زیر نشان داده شده است ایجاد میکنیم:
![]() |
- در [2]، ما با استفاده از NuGet، ارجاعها را به پروژه اضافه میکنیم؛
![]() |
- در [3]، ما مرجع EF 5 را اضافه میکنیم؛
- در [4]، اکنون در مراجع گنجانده شده است؛
![]() |
- در [5]، ما این فرآیند را تکرار میکنیم، این بار [MySQL.Data.Entities] را اضافه میکنیم که یک کانکتور برای Entity Framework (ADO.NET) است. برای یافتن بسته، میتوانید از کادر جستجو برای [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>
- خط ۱۷: رشته اتصال پایگاه داده برای 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] را اجرا کنیم. استثناء زیر بازگردانده میشود:
همان خطا چهار بار ظاهر میشود (خطوط ۲–۵). نوع 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] جایگزین میکنیم. هر دو این آنتوتیشنها دسترسی همزمان را مدیریت میکنند. ما این کار را برای هر چهار موجودیت انجام میدهیم و سپس برنامه را دوباره اجرا میکنیم. سپس خطای زیر را دریافت میکنیم:
خط ۱ به یک خطای نحوی در آنوتیشن SQL که توسط MySQL اجرا شده است، اشاره میکند. از آنجایی که این خطا توسط ما تولید نشده، بلکه توسط ارائهدهنده ADO.NET از MySQL ایجاد شده است، ما نمیتوانیم این مشکل را برطرف کنیم. با این حال، میتوانیم ببینیم که جداول زیر توسط [1] ایجاد شدهاند:
![]() |
- در [2]، میتوان ساختار جداول [clients] و [3] را مشاهده کرد.
چند تغییر باید در پایگاه دادهٔ تولیدشده انجام شود:
- نوع داده ستون [VERSIONING] نادرست است. باید روی نوع MySQL [TIMESTAMP] تنظیم شود؛
- توجه داشته باشید که جدول [rvs] دارای یک محدودیت یکتا است. این محدودیت در طول این تولید ایجاد نشده است؛
- کانکتور ADO.NET از سرور SQL کلیدهای خارجی را با عبارت ON DELETE CASCADE تولید کرده بود. کانکتور ADO.NET برای MySQL این کار را انجام نداد.
همانطور که با سرور SQL انجام دادیم، بنابراین باید پایگاه دادهٔ تولیدشده را اصلاح کنیم. ما نحوهٔ انجام اصلاحات را نشان نمیدهیم. ما صرفاً اسکریپت ایجاد پایگاه داده را ارائه میکنیم:
# SQL مدیر لایت برای 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 بهروزرسانی میشود؛
- خط ۶۳: کلید خارجی از جدول [creneaux] به جدول [medecins] با شرط ON DELETE CASCADE;
- خط ۸۰: محدودیت یکتایی برای جدول [rvs];
- خط ۸۳: کلید خارجی از جدول [rvs] به جدول [creneaux] با شرط ON DELETE CASCADE;
- خط ۸۴: کلید خارجی از جدول [rvs] به جدول [clients] با شرط ON DELETE CASCADE;
اسکریپت تولید جداول پایگاه داده MySQL و [rvmedecins-ef] در پوشه [RdvMedecins / databases / mysql] قرار داده شده است. خواننده میتواند آن را بارگذاری و اجرا کند تا این جداول را ایجاد نماید.
پس از انجام این کار، میتوان برنامههای مختلف پروژه را اجرا کرد. آنها نتایج مشابهی با سرور SQL تولید میکنند، به جز برنامه [ModifyDetachedEntities] که از کار میافتد. برای درک دلیل این موضوع، میتوان به خروجی برنامه [ModifyAtttachedEntities] نگاه کرد:
- خطوط ۱–۲: یک کلاینت قبل از ذخیره شدن زمینه؛
- خطوط ۳–۴: کلاینت پس از ذخیره. این رکورد دارای کلید اصلی است اما برای فیلد [Versioning] خود هیچ مقداری ندارد، در حالی که سرور SQL در حال بهروزرسانی فیلد [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-----------------------------");
// Client1 در زمینه نیست – در حال ویرایش آن
client1.Nom = "y";
// اِنتیتی خارج از زمینه تغییر داده شد
using (var context = new RdvMedecinsContext())
{
// در اینجا ما یک زمینهٔ جدید و خالی داریم
// ما client1 را در حالت اصلاحشده وارد زمینه میکنیم
context.Entry(client1).State = EntityState.Modified;
// زمینه ذخیره میشود
context.SaveChanges();
}
...
}
static void Erase()
{
...
}
static void Dump(string str)
{
...
}
}
}
- خط ۲۰: یک مشتری ذخیره میشود. سپس کلید اصلی آن بر اساس نسخهاش به آن اختصاص داده میشود؛
- خط ۳۳: تغییری در client1 اعمال میشود. این عملیات با شکست مواجه میشود زیرا نسخهٔ ذخیرهشده در پایگاه داده را ندارد.
این مشکل با قرار دادن کد زیر بین خطوط ۲۵ و ۲۶ حل میشود:
// ما client1 را بازیابی میکنیم تا نسخهٔ آن را بهدست آوریم
using (var context = new RdvMedecinsContext())
{
// client2 در زمینه قرار خواهد گرفت
Client client2 = context.Clients.Find(client1.Id);
//نسخهٔ client1 را روی نسخهٔ client2 تنظیم کنید
client1.Versioning = client2.Versioning;
}
اکنون اینتیتی [client1] همان نسخه موجود در پایگاه داده را دارد و بنابراین میتوان از آن برای بهروزرسانی سطر در پایگاه داده استفاده کرد.
4.3. معماری چندلایه مبتنی بر EF 5
بیایید به مطالعه موردی توصیفشده در پاراگراف ۲ بازگردیم.
![]() |
ما با ساخت لایه دسترسی به داده [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 با اطلاعات پایگاه داده 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>
خط ۷ به اسمبلی پروژه [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 for the Web، راهحل را از پوشه [RdvMedecins-MySQL-03] باز میکنیم؛
- در [3]، نام راهحل و نام پروژه را تغییر میدهیم؛
![]() |
- در [4]، ارجاع پروژههای جاری؛
- در [5]، آنها را حذف میکنیم؛
- آنها را با ارجاع به فایلهای 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] تغییر داده شدهاند؛
- پس از ذخیره در پایگاه داده، یک موجودیت Server از نوع SQL هم کلید اصلی و هم Timestamp را داشت. با MySQL، فقط کلید اصلی را داشت. این امر منجر به تغییری در کد شد.
در نهایت، تغییرات نسبتاً اندکی بود، اما ما همچنان مجبور بودیم کد را بازبینی کنیم. ما همین فرآیند را برای سه ورودی دیگر SGBD تکرار میکنیم:
- نسخهٔ اکسپرس دیتابیس اوراکل SGBD نسخهٔ ۱۱ g نسخهٔ ۲؛
- SGBD PostgreSQL 9.2.1;
- SGBD فایربرد ۲.۱.
















