Спадкування типів об’єктів в Oracle, Інші СУБД, Бази даних, статті

Зміст



Введення


Спадкування типів об’єктів – найважливіша властивість об’єктного підходу. В Oracle воно з’явилося з запізненням “на 1,2 версії”, тобто у версії 9.2, а не одразу в 8.0. Але врешті-решт його реалізація виявилася достатньо повною. Це одиничне (не множинне) успадкування, і деякі подробиці його виконання в Oracle ілюструються на прикладі нижче.


Типи в поліклініці


Припустимо, є поліклініка, в приміщенні якої можуть знаходитися співробітники і відвідувачі. У тих і інших є для обліку імена, але у співробітників до того ж табельні номери, а у відвідувачів – номер реєстраційної карти. Класичну ситуацію “типи-підтипи” можна в Oracle дозволити об’єктними засобами, наприклад, так:


CREATE TYPE person_typ AS OBJECT ( name VARCHAR2(30) )
NOT FINAL
/


CREATE TYPE employee_typ UNDER person_typ ( empid NUMBER )
NOT FINAL
/


CREATE TYPE visitor_typ UNDER person_typ ( regid NUMBER )
NOT FINAL
/


Якби фраза NOT FINAL у визначенні PERSON_TYP відсутня, не вдалося б створити підтипи EMPLOYEE_TYP і VISITOR_TYP. У підтипів ж ця фраза залишена на всякий випадок, який зараз випаде. Наприклад, нехай потрібно серед співробітників відрізняти лікарів від обслуговуючого персоналу:


CREATE TYPE doctor_typ UNDER employee_typ
( speciality VARCHAR2(30)
, phone VARCHAR2(7) )
/


CREATE TYPE stuff_typ UNDER employee_typ ( job VARCHAR2(30) )
/


Дані про взаимозависимостях типів можна подивитися в USER_TYPES:


SELECT supertype_name, type_name
FROM user_types
ORDER BY 1, 2;


Люди у прохідній


І відвідувачі, і співробітники проходять через прохідну, де відзначаються в таблиці CHECKPOINT:


CREATE TYPE checkpoint_typ AS OBJECT
( entrytime DATE
, person person_typ )
/


CREATE TABLE checkpoint OF checkpoint_typ;


Ось як вони можуть “проходити”:


INSERT INTO checkpoint VALUES
( SYSDATE
, employee_typ ( “Scott”, 1111 ) );


INSERT INTO checkpoint VALUES
( SYSDATE
, visitor_typ ( “Adams”, 333 ) );


INSERT INTO checkpoint VALUES
( SYSDATE
, doctor_typ ( “Smith”, 2222, “Therapeutist”, “7778899” ) );


INSERT INTO checkpoint VALUES
( SYSDATE
, stuff_typ ( “Alice”, 4444, “Office-cleaner” ) );


Можна перевірити, хто пройшов:


SELECT * FROM checkpoint;


Зверніть увагу на використане спрощення: ніхто не заборонив пройти через прохідну просто співробітнику (Scott), тобто не лікаря і не обслуговуючому персоналу. Бажання заборонити такого роду вставки в таблицю у багатьох випадках виникає цілком законно. Для заборони слід було було описати тип EMPLOYEE_TYP (а заодно і PERSON_TYP) як “абстрактний” (це термін об’єктно-орієнтованого підходу):


CREATE TYPE employee_typ UNDER person_typ ( empid NUMBER )
NOT FINAL
NOT INSTANTIABLE
/


Перегляд входили


Приклад перегляду (SELECT * …) вже наводився. Однак для отримання даних в табличному вигляді запит доведеться ускладнити. Проблема, яку доведеться враховувати в такому запиті – наявність в поле PERSON різних рядків однієї і тієї ж таблиці значень різних типів. Боротися з проблемою дозволяє спеціальне розширення SQL:


SELECT TREAT (person AS person_typ).name FROM checkpoint;


(У дужках зазначу, що на жаль для видачі даних базового типу ANYTYPE в Oracle придумано окреме рішення).


Зверніть увагу, що стовпець для видачі можна формувати, трактуючи поле PERSON відправною таблиці і як, наприклад, EMPLOYEE_TYP, незважаючи на те, що в CHECKPOINT є і рядки іншого типу:


SELECT TREAT (person AS employee_typ).empid FROM checkpoint;


(Дійсно, рядки виводяться навіть для персон, які не є співробітниками, внаслідок чого не мають табельного номера EMPID).


Відбір входили персон конкретного типу можна сформулювати у фразі WHERE, для якої придумані інші спеціальні конструкції:


SELECT * FROM checkpoint WHERE person IS OF (employee_typ);


Зверніть увагу, що видалися рядки з даними типу EMPLOYEE_TYP і всіх його підтипів. Якщо ж рядки з даними підтипів видавати не потрібно, можна зазначити таке:


SELECT * FROM checkpoint WHERE person IS OF (ONLY employee_typ);


Ось як можна об’єднати два наведені вище варіанти відбору – рядків за типами у фразі WHERE і стовпців з атрибутами, можливо інших, типів:


SELECT
SYSDATE,
c.person.name,
TREAT (c.person AS doctor_typ).phone
FROM checkpoint c
WHERE person IS OF (employee_typ);


Зверніть увагу, що по синтаксису, прийнятому в Oracle, написати у фразі SELECT видачу C.PERSON.PHONE, на зразок C.PERSON.NAME, не вийде. Не вийде навіть написати SELECT c.person.empid …, незважаючи на те, що фразою WHERE відбираються співробітники, які мають табельний номер EMPID. Для звернення до властивостей підтипів вам все одно доведеться написати SELECT TREAT (c.person AS doctor_typ). Empid …, вказавши явно підтип, де виникло це властивість. Для властивості NAME приведення типу не потрібно, тому що воно задано для (“основного”) типу стовпця PERSONS, тобто PERSONS_TYP, а не для підтипів PERSONS_TYP.


Плата за вільний прохід чи еволюція типів


На жаль, об’єктні властивості дають розробнику не тільки приємні моменти. Однією з оборотних сторін є складність, більш висока, ніж при роботі з таблицями. У житті далеко не завжди виходить придумати схему даних правильно і відразу, і залишити майбутньому тільки роботу з самими даними. Часто доводиться вносити зміни в схему при наявності вже наявних даних. Тут-то об’єктний підхід і виявить більше труднощів, ніж було б бажано спочатку.


Вище згадувалася змістовно некоректна можливість додати в таблицю CHECKPOINT співробітника Scott, для якої не вказано, чи то він доктор, чи належить обслуговуючому персоналу. Говорилося, як можна виправити ситуацію, надавши типу EMPLOYEE_TYP властивість NOT INSTANTIABLE. Якщо ми захочемо зробити це зараз, то у нас нічого не вийде:


SQL> ALTER TYPE employee_typ NOT INSTANTIABLE;
ALTER TYPE employee_typ NOT INSTANTIABLE
*
ERROR at line 1:
ORA-22327: cannot change a type to NOT INSTANTIABLE if it has dependent tables


На жаль справа не в тому, що в таблиці CHECKPOINT відзначений співробітник, що суперечить зміни властивості типу EMPLOYEE_TYP. Повідомлення про помилку каже, що зміна властивості типу INSTANTIABLE на NOT INSTANTIABLE можливо лише за відсутності таблиць з полями цього типу. На жаль, але нам доведеться пожертвувати таблицею:


DROP TABLE CHECKPOINT;


ALTER TYPE employee_typ NOT INSTANTIABLE CASCADE;


Крім того, оскільки у EMPLOYEE_TYP є підтипи, знадобилося вказати слово CASCADE, щоб зміни поширилися на них (можете перевірити, що вказівка ​​CASCADE не врятує ситуацію з помилкою ORA-22327 вище).


На щастя зворотне зміна властивості типу, з NOT INSTANTIABLE на INSTANTIABLE, не зажадає ніяких жертв і спрацьовує завжди.


У житті складніше


На завершення слід зауважити, що приклад у цій статті був свідомо спрощений. Звичайно, в житті навряд чи було б доцільно в таблицю CHECKPOINT включати об’єктне поле, що зберігає всі модельований властивості людей. (Це відповідає і “фізики процесу”: чи потрібно повідомляти вахтеру спеціалізацію входить лікаря і робочий телефон, досить табельного номера). Персони швидше за все мали б розглядатися як самостійні об’єкти, а в таблицю CHECKPOINT слід було б включити посилання на них. Але для розуміння теми, порушеної в статті, це не суттєво.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*