4. MySQL 5.5.28 ile vaka çalışması
4.1. Araçların kurulumu
Yüklenecek araçlar şunlardır:
- SGBD: [http://dev.mysql.com/downloads/];
- bir yönetim aracı: EMS SQL Manager for MySQL Freeware [http://www.sqlmanager.net/fr/products/mysql/manager/download].
Aşağıdaki örneklerde, root kullanıcısının şifresi root'tur.
MySQL5'i çalıştıralım. Burada bunu Windows hizmetler penceresinden yapıyoruz: [1]. [2]'te, SGBD çalıştırılır.
![]() |
Şimdi, SGBD ve [3]'i yönetmek için [SQL Manager Lite for MySQL] aracını başlatıyoruz.
![]() |
- [4]'te yeni bir veritabanı oluşturuyoruz;
- [5]'te veritabanının adını belirtiyoruz;
![]() |
- [5]'te root / root olarak oturum açıyoruz;
- [6]'te, çalıştırılacak olan SQL komutunu onaylıyoruz;
![]() |
- [7]'te veritabanı oluşturuldu. Şimdi [EMS Manager]'te kaydedilmesi gerekiyor. Bilgiler doğru. [OK] komutunu veriyoruz;
- [8]'e bağlanıyoruz;
- [9]'te, [EMS Manager] veritabanını görüntülüyor; veritabanı şimdilik boş.
Şimdi bu veritabanına bir VS 2012 projesini bağlayacağız.
4.2. Varlıklardan veritabanı oluşturma
Aşağıdaki VS 2012 konsol projesini oluşturuyoruz: [RdvMedecins-MySQL-01] [1]:
![]() |
- [2]'te, NuGet aracılığıyla projeye referanslar ekliyoruz;
![]() |
- [3]'te, EF 5 referansı eklenir;
- [4]'te, artık referanslar arasında yer almaktadır;
![]() |
- [5]'te, bu sefer Entity Framework için bir bağlayıcı olan [MySQL.Data.Entities]'i eklemek üzere işlemi tekrarlıyoruz. Paketi bulmak için [6] arama alanından yararlanabiliriz;
- [7]'te, [MySQL.Data.Entities] ve [MySQL.Data] olmak üzere iki referans görünür; bunlardan ikincisi, birincisinin bağımlılığıdır.
Şimdi, [RdvMedecins-SqlServer-01] projesinden yola çıkarak [RdvMedecins-MySQL-01] projesini oluşturacağız.
![]() |
- [1]'e, seçilen öğeleri kopyalıyoruz;
- [2]'e, bunları [RdvMedecins-MySQL-01] projesine yapıştırıyoruz;
- [3]'te, [Main] yöntemini kullanan birden fazla program olduğu için, projenin başlangıç projesini belirtmemiz gerekir.
Bu aşamada, proje oluşturma işlemi başarılı olmalıdır. Şimdi, veritabanı bağlantı dizesini yapılandıran [App.config] yapılandırma dosyasını ve DbProviderFactory dosyasını değiştireceğiz. Dosya şu şekilde olur:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- Entity Framework yapılandırması hakkında daha fazla bilgi için http://go.microsoft.com/fwlink/?LinkID=237468 adresini ziyaret edin -->
<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>
<!-- bağlantı dizesi-->
<connectionStrings>
<add name="monContexte"
connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<!-- fabrika sağlayıcısı -->
<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. satır: Oluşturduğumuz MySQL [rdvmedecins-ef] veritabanı bağlantı dizesi;
- 24. satır: Sürüm, [1] projesinin [MySql.Data] referansındaki sürümle eşleşmelidir:
![]() |
[Entites.cs] dosyasında da, tabloların adlarının ve ait oldukları şemanın belirtildiği bazı yapılandırma ayarları bulunmaktadır. Bu, SGBD dosyasına göre değişebilir. Burada olduğu gibi, şema olmayacaktır. [Entites.cs] dosyası şu şekilde değişir:
[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] programını çalıştıralım. Aşağıdaki istisna ortaya çıkıyor:
Aynı hata dört kez (2-5. satırlar) ortaya çıkıyor. rowversion türü, varlıklar içindeki [Timestamp] açıklamalı alanı akla getiriyor:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Bu üç satırı aşağıdakilerle değiştirmeye karar verdik:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
Sütunun türünü byte[]'den DateTime'e değiştiriyoruz. Bunu yapmamızın nedeni, MySQL'in tarih/saati temsil eden [TIMESTAMP] türüne sahip olması ve bu türe sahip bir sütunun, satır her güncellendiğinde otomatik olarak MySQL tarafından güncellenmesidir. Bu, eşzamanlı erişimleri yönetmemizi sağlayacaktır.
[Timestamp] anotasyonu yalnızca byte[] türündeki bir sütuna uygulanabilir. Bunu [ConcurrencyCheck] anotasyonuyla değiştiriyoruz. Bu iki anotasyon da eşzamanlı erişimi yönetir. Bunu dört varlık için de yapıp uygulamayı yeniden çalıştırıyoruz. Bunun üzerine şu hatayı alıyoruz:
1. satır, MySQL tarafından yürütülen SQL'te bir sözdizimi hatası olduğunu göstermektedir. Bu hata bizim tarafımızdan değil, MySQL'in sağlayıcısı olan ADO.NET tarafından oluşturulduğundan, bu sorunu düzeltemeyiz. Bununla birlikte, aşağıda [1] tarafından bazı tabloların oluşturulduğu görülebilir:
![]() |
- [2]'te, [clients] ve [3] tablolarının yapısı görülebilir.
Oluşturulan veritabanında yapılması gereken birkaç değişiklik vardır:
- [VERSIONING] sütununun türü uygun değildir. Bu sütuna MySQL [TIMESTAMP] türü verilmelidir;
- [rvs] tablosunun bir benzersizlik kısıtlaması olduğunu hatırlayalım. Bu tablo, bu oluşturma işlemiyle oluşturulmamıştır;
- SQL Sunucusundaki ADO.NET bağlayıcısı, ON, DELETE ve CASCADE maddeleriyle yabancı anahtarlar oluşturmuştu. MySQL'in ADO.NET konektörü ise bunu yapmamıştır.
SQL Sunucusu'nda yaptığımız gibi, bu nedenle oluşturulan veritabanını değiştirmemiz gerekiyor. Değişikliklerin nasıl yapılacağını göstermiyoruz. Sadece veritabanını oluşturma komut dosyasını veriyoruz:
# SQL Manager Lite for MySQL 5.3.0.2
# ---------------------------------------
# Ana Bilgisayar : localhost
# Bağlantı Noktası : 3306
# Veritabanı : 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` tablosunun yapısı:
#
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` tablosunun yapısı:
#
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` tablosunun yapısı:
#
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` tablosunun yapısı:
#
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. satırlar: Tabloların ID birincil anahtarları, AUTO_INCREMENT türündedir, dolayısıyla MySQL tarafından oluşturulmuştur;
- 26, 42, 60, 78: VERSIONING sütunu, TIMESTAMP türündedir ve bir INSERT veya bir UPDATE sırasında güncellenir;
- 63. satır: [creneaux] tablosundan [medecins] tablosuna yönelen yabancı anahtar, ON DELETE CASCADE koşuluyla;
- 80. satır: [rvs] tablosunun teklik kısıtlaması;
- 83. satır: [rvs] tablosundan [creneaux] tablosuna yabancı anahtar, ON, DELETE ve CASCADE koşullarıyla;
- 84. satır: [rvs] tablosundaki yabancı anahtarı, [clients] tablosuna ON, DELETE ve CASCADE koşullarıyla aktarın;
MySQL ve [rvmedecins-ef] veritabanı tablolarını oluşturma komut dosyası, [RdvMedecins / databases / mysql] klasörüne yerleştirilmiştir. Kullanıcı, tablolarını oluşturmak için bu komut dosyasını yükleyip çalıştırabilir.
Bu işlem tamamlandıktan sonra, projenin çeşitli programları çalıştırılabilir. Bu programlar, çöken [ModifyDetachedEntities] programı hariç, SQL Sunucusu ile aynı sonuçları verir. Bunun nedenini anlamak için [ModifyAtttachedEntities] programının sonucuna bakılabilir:
- 1-2. satırlar: bağlamın yedeklenmesinden önceki bir istemci;
- 3-4. satırlar: bağlamın kaydedilmesinden sonraki istemci. Bir birincil anahtara sahip ancak [Versioning] alanının değeri yok; oysa SQL Sunucu, varlığın [Timestamp] alanını güncelliyordu.
Şimdi çökmeye neden olan [ModifyDetachedEntities] programının kodunu inceleyelim:
using System;
...
namespace RdvMedecins_01
{
class ModifyDetachedEntities
{
static void Main(string[] args)
{
Client client1;
// Mevcut veritabanını boşaltıyoruz
Erase();
// bir müşteri ekleniyor
using (var context = new RdvMedecinsContext())
{
// müşteri oluşturma
client1 = new Client { Titre = "x", Nom = "x", Prenom = "x" };
// Müşterinin bağlama eklenmesi
context.Clients.Add(client1);
// bağlam kaydediliyor
context.SaveChanges();
}
// veritabanını görüntüleme
Dump("1-----------------------------");
// müşteri1 bağlamda yok - değiştiriliyor
client1.Nom = "y";
// bağlam dışı varlık değiştiriliyor
using (var context = new RdvMedecinsContext())
{
// burada yeni bir boş bağlam var
// client1'i değiştirilmiş durumda bağlama yerleştiriliyor
context.Entry(client1).State = EntityState.Modified;
// bağlam kaydediliyor
context.SaveChanges();
}
...
}
static void Erase()
{
...
}
static void Dump(string str)
{
...
}
}
}
- 20. satır: Bir müşteri kaydediliyor. Bu sırada, sürüm numarası yerine birincil anahtarı kullanılıyor;
- 33. satır: client1 ile bir değişiklik yapılır. Veritabanındaki sürümle uyuşmadığı için bu işlem başarısız olur.
Sorunu, 25. ve 26. satırlar arasına aşağıdaki kodu ekleyerek çözebiliriz:
// client1'i geri alıp sürümünü alıyoruz
using (var context = new RdvMedecinsContext())
{
// client2 bağlamında yer alacaktır
Client client2 = context.Clients.Find(client1.Id);
// client1'in sürümünü client2'ninkiyle aynı olarak ayarlıyoruz
client1.Versioning = client2.Versioning;
}
Artık [client1] varlığı, veritabanındaki sürümle aynıdır ve bu nedenle veritabanındaki satırı güncellemek için kullanılabilir.
4.3. EF 5'e dayalı çok katmanlı mimari
2. paragrafta açıklanan vaka çalışmamıza geri dönüyoruz.
![]() |
Öncelikle, veri erişim katmanı olan [DAO]'i oluşturacağız. Bunun için, VS 2012 [RdvMedecins-MySQL-02] [1] konsol projesini oluşturuyoruz:
![]() |
- [2]'e, [Common.Logging, EntityFramework, MySql.Data, MySql.Data.Entity, Spring.Core] referansları NuGet ile birlikte eklenir;
- [3]'te, [Models] dosyası [RdvMedecins-MySQL-01] projesinden kopyalanır;
![]() |
- [4]'te, [Dao, Exception, Tests] klasörleri ve [App.config] dosyası, [RdvMedecins-SqlServer-02] projesinden kopyalanır;
- [5]'e, [Program.cs] dosyası silinmiştir;
- [6]'te proje, [DAO] katmanının test programını çalıştıracak şekilde yapılandırılmıştır.
[App.config] dosyasında, SQL Sunucusu veritabanındaki bilgiler, MySQL veritabanındaki bilgilerle değiştirilir. Bu bilgiler, [RdvMedecins-MySQL-01] projesindeki [App.config] dosyasında bulunur:
<!-- bağlantı dizesi-->
<connectionStrings>
<add name="monContexte"
connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<!-- fabrika sağlayıcısı -->
<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 tarafından yönetilen nesneler de değişiyor. Şu anda elimizde şunlar var:
<!-- Spring yapılandırması -->
<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. satır, [RdvMedecins-SqlServer-02] projesinin derlemesine atıfta bulunmaktadır. Derleme artık [RdvMedecins-MySQL-02]'tir.
Bu işlem tamamlandıktan sonra, [DAO] katmanının testini çalıştırmaya hazırız. Öncelikle veritabanını doldurmaya özen göstermeliyiz ([RdvMedecins-MySQL-01] projesindeki [Fill] programı). Test programı başarılı bir şekilde tamamlanır.
[RdvMedecins-SqlServer-02] projesinde yapıldığı gibi, projenin DLL dosyasını oluşturuyoruz ve projeninprojenin tüm DLL dosyalarını, [RdvMedecins-MySQL-02] içinde oluşturulan [lib] klasöründe topluyoruz. Bunlar, takip edecek olan [RdvMedecins-MySQL-03] web projesinin referansları olacaktır.
![]() |
Artık uygulamamızın [ASP.NET] katmanını oluşturmaya hazırız:
![]() |
[RdvMedecins-SqlServer-03] projesinden başlayacağız. Bu projenin klasörünü [RdvMedecins-MySQL-03] ve [1] olarak çoğaltıyoruz:
![]() |
- [2]'e kopyalayacağız; VS 2012 Express for the Web ile [RdvMedecins-MySQL-03] klasöründeki çözümü açacağız;
- [3]'te hem çözümün adını hem de projenin adını değiştiriyoruz;
![]() |
- [4]'te, projenin mevcut referanslarını;
- [5]'te bunları siliyoruz;
- [6] olarak değiştirip, bunları az önce [RdvMedecins-MySQL-02] projesinin [lib] klasörüne kaydettiğimiz DLL dosyasına yapılan referanslarla değiştiriyoruz.
Geriye sadece [Web.config] dosyasını değiştirmek kalıyor. Mevcut içeriğini, [RdvMedecins-MySQL-02] projesindeki [App.config] dosyasının içeriğiyle değiştiriyoruz. Bu işlem tamamlandıktan sonra web projesini çalıştırıyoruz. Çalışıyor.
4.4. Conclusion
SGBD SQL sunucusundan SGBD MySQL sunucusuna geçiş için yapılanları özetleyelim:
- Varlıklara erişim rekabetini yönetmek için kullanılan alan değiştirildi. SQL sunucusundaki hali şöyleydi:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Şu şekilde değiştirilmiştir:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
MySQL ile;
- bir varlığı bir tabloya bağlayan [Table] açıklamaları değiştirildi;
- veritabanı bağlantı dizesi ve [DbProviderFactory], [App.config] ve [Web.config] yapılandırma dosyalarında değiştirildi;
- veritabanına kaydedildikten sonra, bir SQL Server varlığının hem birincil anahtarı hem de Timestamp'i vardı. MySQL ile ise sadece birincil anahtarı vardı. Bu durum bir kod değişikliğine yol açtı.
Sonuç olarak, değişiklikler oldukça azdı ancak yine de kodun gözden geçirilmesi gerekti. Aynı işlemi diğer üç SGBD için de tekrarlıyoruz:
- SGBD Oracle Database Express Edition 11g Sürüm 2;
- SGBD PostgreSQL 9.2.1;
- SGBD Firebird 2.1.
















