5. Приклад використання Oracle Database Express Edition 11g Release 2
5.1. Встановлення інструментів
Необхідно встановити такі інструменти:
- SGBD: [http://www.oracle.com/technetwork/products/express-edition/downloads/index.html];
- інструмент адміністрування: EMS SQL Manager for Oracle Freeware [http://www.sqlmanager.net/fr/products/oracle/manager/download];
- клієнт Oracle для .NET: ODAC 11.2 Release 5 (11.2.0.3.20) з Oracle Developer Tools для 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>
- рядок 3: ім’я користувача та його пароль;
- рядки 6–11: файл DbProviderFactory. У рядку 9 згадується файл DLL [Oracle.DataAccess], якого у нас немає. Його можна отримати за допомогою NuGet та [1]:
![]() |
- у [2] у полі пошуку вводимо ключове слово oracle;
- у [3] виберіть відповідний пакет [Oracle Data Provider]. Це коннектор ADO.NET від Oracle;
![]() |
- у [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 в сутностях. Вносимо ту саму зміну. У сутностях замінюємо три рядки
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
на такі:
[ConcurrencyCheck]
[Column("VERSIONING")]
public int? Versioning { get; set; }
Отже, змінюємо тип стовпця з byte[] на int?. Нагадаємо, що як для SQL Server, так і для MySQL стовпець таблиць, який використовувався для управління конкуренцією доступу, отримував значення з SGBD щоразу, коли вставлявся або змінювався рядок. Відтепер ми будемо використовувати поле сутності, яке буде цілим числом. У SGBD ми будемо використовувати збережені процедури для збільшення цього цілого числа на одиницю щоразу, коли буде вставлено або змінено рядок.
Ми вносимо зазначену зміну для всіх чотирьох сутностей, а потім запускаємо програму знову. Після цього отримуємо таку помилку:
У рядку 1 вказано, що коннектор 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);
}
}
}
}
У рядку 15 запускається виконання класу [RdvMedecinsInitializer] (рядок 12). Він має такий вигляд:
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>
У рядку 2 рядок підключення використовує не ім’я бази даних, а ім’я користувача. Цей користувач має існувати.
Тому нам доводиться вручну створити базу даних [RDVMEDECINS-EF] за допомогою інструменту [EMS Manager for Oracle]. Ми не описуємо всі етапи, а лише найважливіші.
База даних Oracle матиме такий вигляд:
Таблиці
![]() |
Різні таблиці мають первинні та зовнішні ключі, які були у цих самих таблицях у двох попередніх прикладах. Зокрема, зовнішні ключі мають атрибути ON, DELETE та CASCADE.
Послідовності
Тут створено послідовності Oracle. Це генератори послідовних чисел. Їх є 5: [1].
![]() |
- у [2] ми бачимо властивості послідовності [SEQUENCE_CLIENTS]. Вона генерує послідовні числа з кроком 1, починаючи з 1 і аж до дуже великого значення.
Усі послідовності побудовані за одним і тим самим зразком.
- [SEQUENCE_CLIENTS] буде використовуватися для генерації первинного ключа таблиці [CLIENTS];
- [SEQUENCE_MEDECINS] буде використовуватися для генерації первинного ключа таблиці [MEDECINS];
- [SEQUENCE_CRENEAUX] буде використовуватися для генерації первинного ключа таблиці [CRENEAUX];
- [SEQUENCE_RVS] буде використано для генерації первинного ключа таблиці [RVS];
- [SEQUENCE_VERSIONS] буде використовуватися для генерації значень стовпців [VERSIONING] у всіх таблицях.
Тригери
Тригер — це процедура, що виконується SGBD до або після події (вставлення, зміна, видалення) у таблиці. У нас їх 8 [1]:
![]() |
Розглянемо код DDL тригера [TRIGGER_PK_CLIENTS], який заповнює первинний ключ таблиці [CLIENTS]:
- рядки 1–5: перед кожною операцією INSERT над таблицею [CLIENTS];
- рядок 6: стовпець [ID] прийме наступне значення з послідовності [SEQUENCE_CLIENTS]. Таким чином, первинний ключ матиме послідовні значення, що надаються послідовністю.
Тригери [TRIGGER_PK_MEDECINS, TRIGGER_PK_CRENEAUX, TRIGGER_PK_RVS] працюють аналогічно.
Розглянемо код DDL тригера [TRIGGER_VERSIONS_CLIENTS], який заповнює стовпець [VERSIONING] таблиці [CLIENTS]:
- рядки 1–2: перед кожною операцією INSERT або UPDATE над таблицею [CLIENTS];
- рядок 8: стовпець [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]. Тоді виникає нова проблема:
- рядки 1–4: відокремлений клієнт було успішно оновлено;
- рядок 6: відоме виключення. Воно виникає, коли намагаються змінити об’єкт, не маючи правильної версії. Однак у цьому випадку ми хотіли не змінити, а видалити об’єкт:
// видалення сутності поза контекстом
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
Повернемося до нашого прикладу, описаного в параграфі 2 на сторінці 7.
![]() |
Почнемо з побудови шару [DAO] для доступу до даних. Для цього ми дублюємо проект консолі VS 2012 [RdvMedecins-SqlServer-02] у [RdvMedecins-Oracle-02] [1]:
![]() |
- у [2] видаляємо проект [RdvMedecins-SqlServer-02];
![]() |
- у [3] додаємо існуючий проект до рішення. Беремо його з папки [RdvMedecins-Oracle-02], яку щойно створили;
- у [4] новий проєкт має назву того, що було видалено. Ми змінимо його назву;
![]() |
- у [5] ми змінили назву проєкту;
- у [6] ми змінюємо деякі його властивості, наприклад, назву збірки;
- на [7], папку [Models] видалено, щоб замінити її папкою [Models] з проєкту [RdvMedecins-Oracle-01]. Адже обидва проєкти використовують однакові шаблони.
![]() |
- у [8] — поточні посилання проекту;
- у [9] було додано коннектор ADO.NET від Oracle за допомогою інструменту NuGet.
У файлі [App.config] дані з бази SQL Server замінюються даними з бази 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 -->
<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-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 для веб-розробки відкриваємо рішення з папки [RdvMedecins-Oracle-03];
- у [3] ми змінюємо як назву рішення, так і назву проєкту;
![]() |
- у [4] — поточні посилання проекту;
- у [5] видаляємо їх;
- на [6], щоб замінити їх посиланнями на DLL, які ми щойно зберегли у папці [lib] проекту [RdvMedecins-Oracle-02].
Залишилося лише змінити файл [Web.config]. Замінюємо його поточний вміст на вміст файлу [App.config] з проєкту [RdvMedecins-Oracle-02]. Зробивши це, запускаємо веб-проєкт. Він працює. Не забуваємо заповнити базу даних перед запуском веб-додатку.




























