Які найкращі практики моделювання спадкування в базах даних?
Що таке компроміси (наприклад, допитливість)?
(Мене найбільше цікавлять SQL Server і .NET, але я також хочу зрозуміти, як інші платформи вирішують цю проблему.)
Які найкращі практики моделювання спадкування в базах даних?
Що таке компроміси (наприклад, допитливість)?
(Мене найбільше цікавлять SQL Server і .NET, але я також хочу зрозуміти, як інші платформи вирішують цю проблему.)
Відповіді:
Існує кілька способів моделювання спадкування в базі даних. Який ви обираєте, залежить від ваших потреб. Ось кілька варіантів:
Таблиця на тип (TPT)
У кожного класу є своя таблиця. Базовий клас містить усі елементи базового класу в ньому, і кожен клас, який виходить з нього, має свою власну таблицю, з первинним ключем, який також є іноземним ключем до таблиці базового класу; Клас похідної таблиці містить лише різні елементи.
Так, наприклад:
class Person {
public int ID;
public string FirstName;
public string LastName;
}
class Employee : Person {
public DateTime StartDate;
}
Це призведе до таких таблиць, як:
table Person
------------
int id (PK)
string firstname
string lastname
table Employee
--------------
int id (PK, FK)
datetime startdate
Таблиця за перієрархією (TPH)
Є єдина таблиця, яка представляє всю ієрархію спадкування, а значить, кілька стовпців, ймовірно, будуть розрідженими. Додано стовпчик-дискримінатор, який повідомляє системі, що це за тип рядка.
З огляду на класи вище, ви закінчите цю таблицю:
table Person
------------
int id (PK)
int rowtype (0 = "Person", 1 = "Employee")
string firstname
string lastname
datetime startdate
Для будь-яких рядків, що мають рядок 0 (Person), початковий термін завжди буде нульовим.
Стіл на бетон (TPC)
У кожного класу є своя повністю сформована таблиця, без посилань на будь-які інші таблиці.
З огляду на класи вище, ви закінчуєте ці таблиці:
table Person
------------
int id (PK)
string firstname
string lastname
table Employee
--------------
int id (PK)
string firstname
string lastname
datetime startdate
Правильне проектування бази даних - це не що інше, як правильне проектування об'єктів.
Якщо ви плануєте використовувати базу даних для чогось іншого, ніж просто серіалізувати свої об'єкти (наприклад, звіти, запити, використання кількох додатків, бізнес-аналітики тощо), я не рекомендую будь-яке просте відображення від об’єктів до таблиць.
Багато людей думають про рядок у таблиці бази даних як сутність (я багато років думав у цих термінах), але рядок не є сутністю. Це судження. Співвідношення бази даних (тобто таблиця) являє собою деякий факт факту про світ. Наявність рядка вказує на те, що факт є істинним (і навпаки, його відсутність вказує на те, що факт є помилковим).
З огляду на це розуміння, ви бачите, що один тип в об'єктно-орієнтованій програмі може зберігатися через десяток різних відносин. І різноманітність типів (об'єднаних за спадщиною, асоціацією, об'єднанням або зовсім неприєднаними) можуть частково зберігатися в одному відношенні.
Найкраще запитати себе, які факти ви хочете зберігати, на які запитання ви хочете відповісти, які звіти ви хочете створити.
Після того, як буде створено належний дизайн БД, тоді це просто питання створення запитів / представлень, які дозволять вам серіалізувати об'єкти до цих відносин.
Приклад:
У системі бронювання готелів може знадобитися зберігання факту, що у Jane Doe є бронювання номера в Seaview Inn 10-12 квітня. Це атрибут суб’єкта замовника? Це атрибут суб’єкта готелю? Це об'єкт бронювання з властивостями, які включають клієнтів та готелі? Це може бути будь-яка або всі ці речі в об'єктно-орієнтованій системі. У базі даних це нічого такого. Це просто голий факт.
Щоб побачити різницю, розгляньте наступні два запити. (1) Скільки бронювання готелів у Джейн До на наступний рік? (2) Скільки номерів заброньовано на 10 квітня в готелі Seaview Inn?
В об'єктно-орієнтованій системі запит (1) є атрибутом сутності замовника, а запит (2) - атрибутом готельного об'єкта. Це об'єкти, які могли б викрити ці властивості у своїх API. (Хоча, очевидно, внутрішні механізми, за допомогою яких ці значення одержують, можуть містити посилання на інші об'єкти.)
У реляційній системі баз даних обидва запити вивчали беркаційне відношення, щоб отримати їх номери, і концептуально немає необхідності турбуватися з будь-яким іншим "об'єктом".
Таким чином, саме завдяки спробі зберігати факти про світ, а не намагатися зберігати сутності з атрибутами, створюється належна реляційна база даних. І як тільки вона буде розроблена належним чином, то корисні запити, які не були видалені під час проектування, можна легко побудувати, оскільки всі факти, необхідні для виконання цих запитів, знаходяться у своїх місцях.
Employment
таблиця, в якій зібрані всі робочі місця з їх датами початку. Тож якщо Employer
важливо знати поточну дату початку зайнятості , то це може бути правильним випадком використання для особи View
, яка включає це властивість шляхом запиту? (зауважте: здається, що через "-" відразу після мого
Коротка відповідь: ви цього не робите.
Якщо вам потрібно серіалізувати свої об'єкти, використовуйте ORM або ще краще щось на зразок активного запису чи поширеності.
Якщо вам потрібно зберігати дані, зберігайте їх у реляційному порядку (будьте уважні до того, що ви зберігаєте, і звертайте увагу на те, що щойно сказав Джеффрі Л Уітлідж), а не на те, на яке впливає ваш об’єктний дизайн.
Зразки TPT, TPH та TPC - це шляхи, якими ви йдете, як згадував Бред Вілсон. Але пара приміток:
дочірні класи, що успадковують від базового класу, можуть розглядатися як слабкі сутності до визначення базового класу в базі даних, тобто вони залежать від їх базового класу і не можуть існувати без нього. Я неодноразово бачив, що унікальні ідентифікатори зберігаються для кожної дочірньої таблиці, одночасно зберігаючи FK до батьківської таблиці. Одного FK просто достатньо, і ще краще мати каскад на видалення, що дозволяє для відношення FK між дочірніми та базовими таблицями.
У TPT, побачивши лише записи базової таблиці, ви не зможете знайти, який дочірній клас представляє запис. Це іноді потрібно, коли потрібно завантажити список усіх записів (не роблячи це select
на кожній дочірній таблиці). Один із способів впоратися з цим - це мати один стовпчик, що представляє тип дочірнього класу (подібний до поля rowType у TPH), тому якось змішуючи TPT і TPH.
Скажімо, ми хочемо створити базу даних, яка містить таку діаграму класових форм:
public class Shape {
int id;
Color color;
Thickness thickness;
//other fields
}
public class Rectangle : Shape {
Point topLeft;
Point bottomRight;
}
public class Circle : Shape {
Point center;
int radius;
}
Дизайн бази даних для вищевказаних класів може бути таким:
table Shape
-----------
int id; (PK)
int color;
int thichkness;
int rowType; (0 = Rectangle, 1 = Circle, 2 = ...)
table Rectangle
----------
int ShapeID; (FK on delete cascade)
int topLeftX;
int topLeftY;
int bottomRightX;
int bottomRightY;
table Circle
----------
int ShapeID; (FK on delete cascade)
int centerX;
int center;
int radius;
Є два основні типи успадкування, які ви можете налаштувати в БД, таблицю за суттю та таблицю за Ієрархією.
Таблиця на сутність - це таблиця базової сутності, яка має спільні властивості всіх дочірніх класів. Тоді ви маєте для кожного дочірнього класу іншу таблицю, у якій лише властивості, застосовні до цього класу. Вони пов'язані 1: 1 своїми ПК
Таблиця за ієрархією - це те, коли всі класи поділяють таблицю, а необов'язкові властивості є нульовими. Їх також є полем дискримінації, яке є числом, яке позначає тип, який в даний час містить запис
SessionTypeID є дискримінатором
Ціль на ієрархію швидше запитувати, оскільки вам не потрібні приєднання (лише значення дискримінатора), тоді як цільовій для кожної особи потрібно робити складні об'єднання, щоб виявити, що таке щось, а також відновити всі його дані ..
Редагувати: зображення, які я показую тут, - це знімки екрана проекту, над яким я працюю. Зображення Asset не є повним, отже, порожнечею, але це було головним чином, щоб показати, як його налаштування, а не що розмістити всередині ваших таблиць. Це залежить від вас;). Таблиця сеансів містить інформацію про сеанси віртуальної співпраці та може бути декількох типів сеансів, залежно від типу співпраці.
Ви б нормалізували свою базу даних, і це насправді відобразило б ваше спадщину. Це може призвести до погіршення продуктивності, але саме так відбувається з нормалізацією. Ймовірно, вам доведеться використовувати здоровий глузд, щоб знайти баланс.
повторення подібної відповіді теми
У ІЛИ зіставлянні карти спадкування відображається у батьківській таблиці, де батьківські та дочірні таблиці використовують один ідентифікатор
наприклад
create table Object (
Id int NOT NULL --primary key, auto-increment
Name varchar(32)
)
create table SubObject (
Id int NOT NULL --primary key and also foreign key to Object
Description varchar(32)
)
SubObject має зовнішній ключ до Object. коли ви створюєте рядок SubObject, спочатку слід створити рядок Object та використовувати Id в обох рядках
EDIT: якщо ви також шукаєте моделювати поведінку, вам знадобиться таблиця Type, яка перераховує відносини успадковування між таблицями та вказує назву складання та класу, які реалізували поведінку кожної таблиці
здається, надмірність, але все залежить від того, для чого ви хочете її використовувати!
Використовуючи SQL ALchemy (Python ORM), ви можете зробити два типи успадкування.
Я мав досвід використання сингл-таблиці та розбірливого стовпчика. Наприклад, база даних Sheep (не жартуйте!) Зберігала всі вівці в одній таблиці, а Овен та Овець оброблялися за допомогою гендерного стовпця в цій таблиці.
Таким чином, ви можете запитувати всіх овець і отримувати всіх овець. Або ви можете запитувати лише Рама, і він отримає лише Рамс. Ви також можете робити такі речі, як стосунки, які можуть бути лише Барана (тобто, Сир Вівці) тощо.
Зауважимо, що деякі двигуни бази даних вже надають механізми успадковування на зразок Postgres . Подивіться на документацію .
Наприклад, ви б запитали систему персоналу / працівника, описану у відповіді вище, як це:
/ * Тут відображається ім’я всіх осіб або службовців * / ВИБІРТЕ ім’я від особи; / * Тут відображається дата початку роботи лише всіх працівників * / ВИБІРАТИ початок від працівника;
Оскільки це вибір вашої бази даних, вам не потрібно бути особливо розумним!