5. مطالعه موردی با Oracle Database Express Edition 11g نسخه ۲
5.1. نصب ابزارها
ابزارهای قابل نصب به شرح زیر هستند:
- SGBD: [http://www.oracle.com/technetwork/products/express-edition/downloads/index.html];
- یک ابزار مدیریتی: EMS SQL مدیر برای Oracle Freeware [http://www.sqlmanager.net/fr/products/oracle/manager/download];
- یک کلاینت Oracle برای .NET: ODAC نسخه 5 انتشار 11.2 (11.2.0.3.20) به همراه ابزارهای توسعه Oracle برای Visual Studio: [http://www.oracle.com/technetwork/developer-tools/visual-studio/downloads/index.html].
در مثالهای زیر، کاربر «system» رمز عبور «system» را دارد.
بیایید Oracle [1] را راهاندازی کنیم و سپس ابزار [SQL Manager Lite for Oracle] را که برای مدیریت SGBD و [2] استفاده خواهیم کرد.
![]() |
- در [3]، ما به یک پایگاه داده موجود متصل میشویم؛
![]() |
- در [4]، از سرویس Oracle با نام XE برای اتصال استفاده میکنیم؛
- در [5]، نام پایگاه داده XE را مشخص میکنیم؛
- در [6]، با نام کاربری system / system وارد میشویم؛
- در [7]، ما جادوگر را تکمیل میکنیم؛
![]() |
- در [8]، شما به پایگاه داده وارد میشوید؛
- در [9]، شما وارد شدهاید؛
- چون با کاربر «system / system» که دارای امتیازات ویژه است وارد شدهایم، میتوانیم برای مثال کاربران را مدیریت کنیم [10];
![]() |
- در [11]، ما یک کاربر جدید ایجاد میکنیم؛
- بهعنوان [12]، آنها [RDVMEDECINS-EF] نامیده خواهند شد؛
- در [13]، و رمز عبور آن rdvmedecins خواهد بود؛
- در [14]، ایجاد کاربر تأیید میشود؛
- در [15]، کاربر ایجاد شده است؛
![]() |
- در [16]، کاربر [RDVMEDECINS-EF] همچنین یک طرح پایگاه داده است؛
- در [17]، کاربری که ایجاد شده است، حقوق کافی ندارد. ما این حقوق را از طریق یک اسکریپت SQL به او اعطا میکنیم؛
![]() |
- در [18]، اسکریپت اجرا میشود؛
- در [19]، ما تلاش خواهیم کرد تا با حساب [RDVMEDECINS-EF] وارد سیستم شویم تا ببینیم چه کارهایی میتوانند انجام دهند. برای این کار، ابتدا با ثبت یک پایگاه داده جدید در [EMS Manager] شروع میکنیم؛
![]() |
- در [19]، ما از طریق سرویس XE وارد سیستم میشویم؛
- در [20]، ما با شناسه RDVMEDECINS-EF / rdvmedecins وارد سیستم میشویم؛
- در [21]، یک نام مستعار ارائه میشود که نام کاربر واردشده را منعکس میکند؛
- در [22]، شما با استفاده از اطلاعات ارائهشده وارد Oracle میشوید؛
![]() |
![]() |
- در [22]، ما موفق به اتصال شدیم؛
- در [23]، ما در حال تلاش برای ایجاد یک جدول در طرحواره [RDVMEDECINS-EF] هستیم؛
- در [24]، یک جدول تعریف میکنیم؛
- در [25]، تعریف آن را اعتبارسنجی میکنیم؛
![]() |
- در [26]، جدول ایجاد شده است. ما آن را حذف میکنیم؛
- در [27]، آن حذف شده است.
اکنون که یک کاربر با حقوق کافی داریم، پروژه VS 2012 را ایجاد میکنیم که بر اساس تعریف موجودهها، جداول را در طرح [RDVMEDECINS-EF] ایجاد خواهد کرد.
5.2. ایجاد پایگاه داده از روی انتیتها
ما با کپی کردن پوشه پروژه [RdvMedecins-SqlServer-01] به [RdvMedecins-Oracle-01] و [1] شروع میکنیم:
![]() |
- به [2]؛ در VS 2012، پروژه [RdvMedecins-SqlServer-01] را از راهحل حذف میکنیم؛
![]() |
- در [3]، پروژه حذف شده است؛
- در [4]، یکی دیگر اضافه میکنیم. این مورد از پوشه [RdvMedecins-Oracle-01] که قبلاً ایجاد کرده بودیم، گرفته شده است؛
![]() |
- در [5]، پروژهای که بارگذاری شده [RdvMedecins-SqlServer-01] نام دارد؛
- در [6]، نام آن را به [RdvMedecins-Oracle-01] تغییر میدهیم
![]() |
- در [7]، یک پروژه دیگر به راهحل اضافه میشود. این پروژه از پوشه [RdvMedecins-SqlServer-01] پروژهای گرفته شده است که قبلاً از راهحل حذف کرده بودیم؛
- در [8]، پروژه [RdvMedecins-SqlServer-01] مجدداً به راهحل اضافه شده است.
پروژه [RdvMedecins-Oracle-01] با پروژه [RdvMedecins-SqlServer-01] یکسان است. ما باید چند تغییر ایجاد کنیم. در [App.config]، ما رشته اتصال و [DbProviderFactory] را اصلاح خواهیم کرد که باید برای هر SGBD تطبیق داده شود.
<!-- رشته اتصال برای پایگاه داده -->
<connectionStrings>
<add name="monContexte" connectionString="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User Id=RDVMEDECINS-EF;Password=rdvmedecins;" providerName="Oracle.DataAccess.Client" />
</connectionStrings>
<!-- ارائهدهنده فابریک -->
<system.data>
<DbProviderFactories>
<remove invariant="Oracle.DataAccess.Client" />
<add name="Oracle Data Provider for .NET" invariant="Oracle.DataAccess.Client" description="Oracle Data Provider for .NET" type="Oracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess, Version=4.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
</DbProviderFactories>
</system.data>
- خط ۳: نام کاربری و رمز عبور آن؛
- خطوط ۶–۱۱: DbProviderFactory. خط ۹ به DLL و [Oracle.DataAccess] اشاره دارد که ما نداریم. ما میتوانیم آن را با استفاده از NuGet و [1] بهدست آوریم:
![]() |
- برای [2]، کلمه کلیدی oracle را در کادر جستجو وارد کنید؛
- برای [3]، بسته صحیح [Oracle Data Provider] را انتخاب کنید. این کانکتور Oracle ADO.NET است؛
![]() |
- در [4]، مرجع اضافه شده است؛
- در [5]، در داخل [App.config]، باید نسخه صحیح DLL را وارد کنید. این نسخه را میتوانید در ویژگیهای آن پیدا کنید.
در فایل [Entites.cs]، باید اسکیما را برای جداول تولیدشده تطبیق دهید. اسکیمای مورد استفاده، نام کاربری است که مالک جداول میباشد.
[Table("MEDECINS", Schema = "RDVMEDECINS-EF")]
public class Medecin : Personne
{...}
[Table("CLIENTS", Schema = "RDVMEDECINS-EF")]
public class Client : Personne
{...}
[Table("RVS", Schema = "RDVMEDECINS-EF")]
public class Rv
{...}
[Table("CRENEAUX", Schema = "RDVMEDECINS-EF")]
public class Creneau
{...}
ما ساخت پروژه را پیکربندی میکنیم:
![]() |
- در [1]، ما نام متفاوتی را برای اسمبلیای که قرار است تولید شود، تعیین میکنیم؛
- در [2]، ما همچنین یک فضای نام پیشفرض متفاوت را مشخص میکنیم؛
- در [3]، برنامهٔ اجرایی را مشخص میکنیم.
در این مرحله، هیچ خطای کامپایل وجود ندارد. بیایید برنامه [CreateDB_01] را اجرا کنیم. استثناء زیر را دریافت میکنیم:
به یاد داریم که با MySQL نیز با همین خطا مواجه شده بودیم. این مربوط به نوع فیلد Timestamp در entities است. ما همان تغییر را اعمال میکنیم. در entities، سه خط را جایگزین میکنیم
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
با موارد زیر جایگزین میکنیم:
[ConcurrencyCheck]
[Column("VERSIONING")]
public int? Versioning { get; set; }
بنابراین نوع ستون را از byte[] به int? تغییر میدهیم. به یاد داریم که برای هر دو سرور SQL و MySQL، ستون جدول مورد استفاده برای مدیریت دسترسی همزمان، هر بار که یک سطر درج یا بهروزرسانی میشد، مقداری از SGBD دریافت میکرد. از این پس، از یک فیلد انتیتایتی که عدد صحیح است استفاده خواهیم کرد. در SGBD، از رویههای ذخیرهشده برای افزایش این عدد صحیح به اندازه یک واحد در هر بار درج یا بهروزرسانی یک سطر استفاده خواهیم کرد.
ما تغییر فوق را در هر چهار موجودیت اعمال میکنیم و سپس برنامه را مجدداً اجرا میکنیم. سپس خطای زیر را دریافت میکنیم:
خط ۱ نشان میدهد که کانکتور Oracle با شناسه ADO.NET قادر به حذف پایگاه داده موجود نیست. بیایید خلاصهای از آنچه در حال رخ دادن است ارائه دهیم. کد مربوط به [CreateDB_01.cs] به شرح زیر است:
using System;
using System.Data.Entity;
using RdvMedecins.Models;
namespace RdvMedecins_01
{
class CreateDB_01
{
static void Main(string[] args)
{
// ایجاد پایگاه داده
Database.SetInitializer(new RdvMedecinsInitializer());
using (var context = new RdvMedecinsContext())
{
context.Database.Initialize(false);
}
}
}
}
خط ۱۵ اجرای کلاس [RdvMedecinsInitializer] (خط ۱۲) را فعال میکند. به شرح زیر:
public class RdvMedecinsInitializer : DropCreateDatabaseAlways<RdvMedecinsContext>
این از کلاس [DropCreateDatabaseAlways] مشتق شده است که تلاش میکند پایگاه داده را حذف کرده و سپس دوباره ایجاد کند. ما تعریف کلاس را به این صورت تغییر میدهیم:
public class RdvMedecinsInitializer : CreateDatabaseIfNotExists<RdvMedecinsContext>
پایگاه داده فقط در صورتی ایجاد میشود که از قبل وجود نداشته باشد. ما دوباره [CreateDB_01.cs] را اجرا میکنیم و این بار دیگر خطایی وجود ندارد. با این حال، در [EMS Manager]، میتوانیم ببینیم که پایگاه داده [RDVMEDECINS-EF] خالی باقی مانده است. چون EF 5 پایگاهدادهٔ موجود را پیدا کرد، هیچ کاری انجام نداد. این دستور تنها در صورتی اقدام میکند که پایگاهداده وجود نداشته باشد. از آن نقطه به بعد، ما در یک چرخهٔ بیپایان میچرخیم. در واقع، رشتهٔ اتصال برای SGBD به شرح زیر است:
<connectionStrings>
<add name="monContexte" connectionString="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User Id=RDVMEDECINS-EF;Password=rdvmedecins;" providerName="Oracle.DataAccess.Client" />
</connectionStrings>
در خط ۲، رشته اتصال به جای نام پایگاه داده از نام کاربری استفاده میکند. این نام کاربری باید وجود داشته باشد.
بنابراین، ما ملزم به ایجاد دستی پایگاه داده [RDVMEDECINS-EF] با استفاده از ابزار [EMS Manager for Oracle] هستیم. ما تمام مراحل را توضیح نمیدهیم، بلکه فقط مهمترین مراحل را بیان میکنیم.
پایگاه داده Oracle به شرح زیر خواهد بود:
جدولها
![]() |
جدولهای مختلف دارای کلیدهای اصلی و خارجی یکسانی با جدولهای متناظر در دو مثال قبلی هستند. کلیدهای خارجی شامل ویژگیهای ON، DELETE و CASCADE هستند.
پیوستارها
توالیهای Oracle در اینجا ایجاد شدهاند. اینها تولیدکنندههای اعداد متوالی هستند. تعداد آنها پنج عدد است: [1].
![]() |
- در [2]، میتوانیم ویژگیهای دنباله [SEQUENCE_CLIENTS] را مشاهده کنیم. این دنباله اعداد متوالی را با گام ۱، از ۱ شروع کرده و تا یک مقدار بسیار بزرگ تولید میکند.
تمام توالیها بر اساس یک مدل یکسان ساخته شدهاند.
- [SEQUENCE_CLIENTS] برای تولید کلید اصلی برای جدول [CLIENTS] استفاده خواهد شد؛
- [SEQUENCE_MEDECINS] برای تولید کلید اصلی جدول [MEDECINS] استفاده خواهد شد؛
- [SEQUENCE_CRENEAUX] برای تولید کلید اصلی جدول [CRENEAUX] استفاده خواهد شد؛
- [SEQUENCE_RVS] برای تولید کلید اصلی جدول [RVS] استفاده خواهد شد؛
- [SEQUENCE_VERSIONS] برای تولید مقادیر ستونهای [VERSIONING] در تمام جداول استفاده خواهد شد.
تریگرها
یک تله (Trigger) روندی است که توسط SGBD قبل یا بعد از یک رویداد (درج، بهروزرسانی، حذف) در یک جدول اجرا میشود. ما ۸ تله داریم: [1]:
![]() |
بیایید نگاهی به کد تریگر DDL بیندازیم که کلید اصلی جدول [TRIGGER_PK_CLIENTS] را پر میکند:
- خطوط ۱–۵: قبل از هر عملیات INSERT روی جدول [CLIENTS]؛
- خط ۶: ستون [ID] مقدار بعدی را از دنباله [SEQUENCE_CLIENTS] دریافت خواهد کرد. بدین ترتیب کلید اصلی دارای مقادیر متوالی تأمینشده توسط دنباله خواهد بود.
تریگرهای [TRIGGER_PK_MEDECINS, TRIGGER_PK_CRENEAUX, TRIGGER_PK_RVS] به روشی مشابه عمل میکنند.
بیایید کد DDL برای تله [TRIGGER_VERSIONS_CLIENTS] را بررسی کنیم که ستون [VERSIONING] در جدول [CLIENTS] را پر میکند:
- خطوط ۱–۲: قبل از هر عملیات INSERT یا UPDATE روی جدول [CLIENTS]؛
- خط ۸: ستون [VERSIONING] مقدار بعدی را از دنباله [SEQUENCE_VERSIONS] دریافت خواهد کرد. بنابراین ستون [VERSIONING] مقادیر متوالی را از این دنباله دریافت میکند.
تریگرهای [TRIGGER_VERSION_MEDECINS, TRIGGER_VERSION_CRENEAUX, TRIGGER_VERSION_RVS] به روشی مشابه عمل میکنند. چهار ستون [VERSIONING] مقادیر خود را از همان دنباله استخراج میکنند.
اسکریپت ایجاد جداول پایگاه داده Oracle، [RDVMEDECINS-EF]، در پوشه [RdvMedecins / databases / oracle] قرار داده شده است. خواننده میتواند آن را بارگذاری و اجرا کند تا جداول را ایجاد نماید.
پس از انجام این کار، میتوان برنامههای مختلف پروژه را اجرا کرد. آنها نتایج مشابهی با سرور SQL تولید میکنند، به جز برنامه [ModifyDetachedEntities] که به همان دلیلی که با MySQL از کار میافتاد، کرش میکند. این مشکل به همان روش حل میشود. کافی است برنامه [ModifyDetachedEntities] را از پروژه [RdvMedecins-MySQL-01] به پروژه [RdvMedecins-Oracle-01] کپی کنید. این کار مشکل جدیدی را ایجاد میکند:
- خطوط ۱–۴: کلاینت جداشده در واقع بهروزرسانی شده است؛
- خط ۶: یک استثنای شناختهشده. این همان استثنایی است که هنگام تلاش برای تغییر یک موجودیت بدون داشتن نسخه صحیح رخ میدهد. با این حال، در این مورد، ما نمیخواستیم موجودیت را تغییر دهیم، بلکه میخواستیم آن را حذف کنیم:
//حذف انتیت از خارج از زمینه
using (var context = new RdvMedecinsContext())
{
// در اینجا ما یک زمینهٔ جدید و خالی داریم
// ما client1 را در حالت حذفشده در زمینه قرار میدهیم
context.Entry(client1).State = EntityState.Deleted;
// ما زمینه را ذخیره میکنیم
context.SaveChanges();
}
EF 5 از حذف client1 از پایگاه داده خودداری کرد، زیرا client1 (خط 6) نسخه یکسان نبود. ما با MySQL با این مشکل مواجه نشده بودیم. ما به تدریج متوجه میشویم که کانکتورهای ADO.NET برای موجودیتهای مختلف SGBD تفاوتهای جزئی نشان میدهند. ما این مشکل را به شرح زیر اصلاح میکنیم:
using (var context = new RdvMedecinsContext())
{
// در اینجا یک زمینهٔ خالی جدید داریم
//ما client1 را در زمینه قرار میدهیم تا آن را حذف کنیم
context.Clients.Remove(context.Clients.Find(client1.Id));
// زمینه ذخیره میشود
context.SaveChanges();
}
و این کار میکند.
5.3. معماری چندلایه مبتنی بر EF 5
به مطالعه موردی خود که در پاراگراف ۲ صفحه ۷ توصیف شده است بازمیگردیم.
![]() |
ما با ساخت لایه دسترسی به داده [DAO] شروع میکنیم. برای این کار، پروژهٔ کنسول VS 2012 [RdvMedecins-SqlServer-02] را در [RdvMedecins-Oracle-02] [1] کپی میکنیم:
![]() |
- به [2]، و پروژه [RdvMedecins-SqlServer-02] را حذف کنید؛
![]() |
- در [3]، یک پروژه موجود به راهحل اضافه میشود. این پروژه از پوشه [RdvMedecins-Oracle-02] که به تازگی ایجاد شده است، گرفته شده است؛
- در [4]، پروژه جدید همان نام پروژهای را دارد که حذف شده بود. ما آن را نامگذاری مجدد خواهیم کرد؛
![]() |
- در [5]، نام پروژه را تغییر دادهایم؛
- در [6]، ما در حال تغییر برخی از ویژگیهای آن هستیم، مانند نام assembly در اینجا؛
- به [7]؛ پوشه [Models] حذف شده و با پوشه [Models] از پروژه [RdvMedecins-Oracle-01] جایگزین میشود. این به این دلیل است که این دو پروژه از همان قالبها استفاده میکنند.
![]() |
- در [8]، پروژههای جاری ارجاع میدهند؛
- در [9]، کانکتور Oracle با استفاده از ابزار NuGet اضافه شده است.
در فایل [App.config]، اطلاعات موجود در پایگاه داده سرور SQL با اطلاعات پایگاه داده Oracle جایگزین شده است. این اطلاعات را میتوان در فایل [App.config] در پروژه [RdvMedecins-Oracle-01] یافت:
<!-- رشته اتصال به پایگاه داده -->
<connectionStrings>
<add name="monContexte" connectionString="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User Id=RDVMEDECINS-EF;Password=rdvmedecins;" providerName="Oracle.DataAccess.Client" />
</connectionStrings>
<!-- ارائهدهندهٔ کارخانه -->
<system.data>
<DbProviderFactories>
<remove invariant="Oracle.DataAccess.Client" />
<add name="Oracle Data Provider for .NET" invariant="Oracle.DataAccess.Client" description="Oracle Data Provider for .NET" type="Oracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess, Version=4.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
</DbProviderFactories>
</system.data>
ابجکتهای مدیریتشده توسط 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-Oracle-02] است.
با انجام این کار، ما آمادهایم تا تست لایه [DAO] را اجرا کنیم. پیش از انجام این کار، باید اطمینان حاصل کنیم که پایگاه داده پر شده است (برنامه [Fill] از پروژه [RdvMedecins-Oracle-01]). برنامه تست با موفقیت اجرا میشود.
ما DLL را برای پروژه به همان روشی که برای پروژه [RdvMedecins-SqlServer-02] انجام دادیم، ایجاد میکنیم و جمعآوری میکنیمتمام فایلهای DLL پروژه را در پوشهای به نام [lib] که در داخل [RdvMedecins-Oracle-02] ایجاد شده است، کامپایل میکنیم. اینها ارجاعات برای پروژه وب [RdvMedecins-Oracle-03] بعدی خواهند بود.
![]() |
اکنون آماده ساخت لایه [ASP.NET] برنامه خود هستیم:
![]() |
ما با پروژه [RdvMedecins-SqlServer-03] شروع خواهیم کرد. ما پوشه این پروژه را در [RdvMedecins-Oracle-03] و [1] کپی خواهیم کرد:
![]() |
- به [2]، با استفاده از VS 2012 Express for the Web، راهحل را از پوشه [RdvMedecins-Oracle-03] باز میکنیم؛
- در [3]، ما هم نام راهحل و هم نام پروژه را تغییر میدهیم؛
![]() |
- در [4]، ارجاعات پروژهٔ جاری؛
- در [5]، آنها را حذف میکنیم؛
- آنها را با ارجاع به فایلهای DLL که به تازگی در پوشهای به نام [lib] در پروژه [RdvMedecins-Oracle-02] ذخیره کردهایم، جایگزین میکنیم.
تنها کاری که باقی مانده، ویرایش فایل [Web.config] است. ما محتوای فعلی آن را با محتوای فایل [App.config] از پروژه [RdvMedecins-Oracle-02] جایگزین میکنیم. پس از انجام این کار، پروژه وب را اجرا میکنیم. کار میکند. قبل از اجرای برنامه وب، فراموش نکنید که پایگاه داده را پر کنید.




























