Các thực hành tốt nhất để mô hình kế thừa trong cơ sở dữ liệu là gì?
Sự đánh đổi (ví dụ như queritable) là gì?
(Tôi quan tâm nhất đến SQL Server và .NET, nhưng tôi cũng muốn hiểu cách các nền tảng khác giải quyết vấn đề này.)
Các thực hành tốt nhất để mô hình kế thừa trong cơ sở dữ liệu là gì?
Sự đánh đổi (ví dụ như queritable) là gì?
(Tôi quan tâm nhất đến SQL Server và .NET, nhưng tôi cũng muốn hiểu cách các nền tảng khác giải quyết vấn đề này.)
Câu trả lời:
Có một số cách để mô hình kế thừa trong cơ sở dữ liệu. Mà bạn chọn phụ thuộc vào nhu cầu của bạn. Dưới đây là một vài lựa chọn:
Bảng mỗi loại (TPT)
Mỗi lớp có một bảng riêng. Lớp cơ sở có tất cả các thành phần lớp cơ sở trong nó và mỗi lớp xuất phát từ nó có bảng riêng, với khóa chính cũng là khóa ngoại đối với bảng lớp cơ sở; lớp của bảng dẫn xuất chỉ chứa các phần tử khác nhau.
Ví dụ:
class Person {
public int ID;
public string FirstName;
public string LastName;
}
class Employee : Person {
public DateTime StartDate;
}
Sẽ dẫn đến các bảng như:
table Person
------------
int id (PK)
string firstname
string lastname
table Employee
--------------
int id (PK, FK)
datetime startdate
Bảng theo thứ bậc (TPH)
Có một bảng duy nhất đại diện cho tất cả hệ thống phân cấp thừa kế, có nghĩa là một số cột có thể sẽ thưa thớt. Một cột phân biệt được thêm vào để cho hệ thống biết loại hàng này là gì.
Với các lớp ở trên, bạn kết thúc với bảng này:
table Person
------------
int id (PK)
int rowtype (0 = "Person", 1 = "Employee")
string firstname
string lastname
datetime startdate
Đối với bất kỳ hàng nào là rowtype 0 (Person), startdate sẽ luôn là null.
Bảng-Bê tông (TPC)
Mỗi lớp có bảng được tạo hoàn chỉnh riêng mà không có tham chiếu nào đến bất kỳ bảng nào khác.
Với các lớp ở trên, bạn kết thúc với các bảng sau:
table Person
------------
int id (PK)
string firstname
string lastname
table Employee
--------------
int id (PK)
string firstname
string lastname
datetime startdate
Thiết kế cơ sở dữ liệu phù hợp là không có gì giống như thiết kế đối tượng thích hợp.
Nếu bạn đang dự định sử dụng cơ sở dữ liệu cho bất kỳ thứ gì ngoài việc đơn giản hóa việc sắp xếp các đối tượng của bạn (như báo cáo, truy vấn, sử dụng đa ứng dụng, kinh doanh thông minh, v.v.) thì tôi không khuyến nghị bất kỳ loại ánh xạ đơn giản nào từ các đối tượng vào bảng.
Nhiều người nghĩ về một hàng trong bảng cơ sở dữ liệu như một thực thể (tôi đã dành nhiều năm để suy nghĩ theo các thuật ngữ đó), nhưng một hàng không phải là một thực thể. Đó là một đề xuất. Một quan hệ cơ sở dữ liệu (nghĩa là bảng) đại diện cho một số tuyên bố thực tế về thế giới. Sự hiện diện của hàng chỉ ra thực tế là đúng (và ngược lại, sự vắng mặt của nó cho thấy thực tế là sai).
Với sự hiểu biết này, bạn có thể thấy rằng một loại duy nhất trong một chương trình hướng đối tượng có thể được lưu trữ trên một tá các mối quan hệ khác nhau. Và một loạt các loại (thống nhất bởi sự kế thừa, liên kết, tập hợp hoặc hoàn toàn không liên kết) có thể được lưu trữ một phần trong một mối quan hệ duy nhất.
Tốt nhất bạn nên tự hỏi mình, bạn muốn lưu trữ những sự thật nào, câu hỏi nào bạn muốn có câu trả lời, bạn muốn tạo báo cáo nào.
Khi thiết kế DB phù hợp được tạo, thì việc tạo truy vấn / khung nhìn cho phép bạn tuần tự hóa các đối tượng của mình theo các mối quan hệ đó là một vấn đề đơn giản.
Thí dụ:
Trong một hệ thống đặt phòng khách sạn, bạn có thể cần lưu trữ thực tế rằng Jane Doe có đặt phòng cho Seaview Inn cho ngày 10-12 tháng 4. Đó có phải là một thuộc tính của thực thể khách hàng? Nó có phải là một thuộc tính của thực thể khách sạn? Đây có phải là một thực thể đặt phòng với các tài sản bao gồm khách hàng và khách sạn? Nó có thể là bất kỳ hoặc tất cả những điều đó trong một hệ thống hướng đối tượng. Trong một cơ sở dữ liệu, nó không phải là một trong những điều đó. Nó chỉ đơn giản là một sự thật trần trụi.
Để thấy sự khác biệt, hãy xem xét hai truy vấn sau đây. (1) Jane Doe có bao nhiêu đặt phòng khách sạn cho năm tới? (2) Có bao nhiêu phòng được đặt cho ngày 10 tháng 4 tại Seaview Inn?
Trong một hệ thống hướng đối tượng, truy vấn (1) là một thuộc tính của thực thể khách hàng và truy vấn (2) là một thuộc tính của thực thể khách sạn. Đó là những đối tượng sẽ phơi bày các thuộc tính đó trong API của họ. (Mặc dù, rõ ràng các cơ chế bên trong mà các giá trị đó thu được có thể liên quan đến các tham chiếu đến các đối tượng khác.)
Trong một hệ thống cơ sở dữ liệu quan hệ, cả hai truy vấn sẽ kiểm tra mối quan hệ đặt trước để lấy số của chúng và về mặt khái niệm không cần phải bận tâm với bất kỳ "thực thể" nào khác.
Vì vậy, đó là bằng cách cố gắng lưu trữ các sự kiện về thế giới, thay vì cố gắng lưu trữ các thực thể với các thuộc tính, một cơ sở dữ liệu quan hệ phù hợp được xây dựng. Và một khi nó được thiết kế đúng, thì có thể dễ dàng xây dựng các truy vấn hữu ích trong giai đoạn thiết kế, vì tất cả các sự kiện cần thiết để thực hiện các truy vấn đó đều nằm ở vị trí thích hợp của chúng.
Employment
bảng, thu thập tất cả các việc làm với ngày bắt đầu của họ. Vì vậy, nếu biết ngày bắt đầu việc làm hiện tại của một Employer
là quan trọng, đó có thể là trường hợp sử dụng thích hợp cho một View
, bao gồm tài sản đó bằng cách truy vấn? (lưu ý: dường như vì '-' ngay sau nick của tôi, tôi không nhận được bất kỳ thông báo nào về bình luận của bạn)
Câu trả lời ngắn gọn: bạn không.
Nếu bạn cần tuần tự hóa các đối tượng của mình, hãy sử dụng ORM hoặc thậm chí tốt hơn những thứ như Activerecord hoặc thịnh hành.
Nếu bạn cần lưu trữ dữ liệu, hãy lưu trữ dữ liệu theo cách liên quan (cẩn thận với những gì bạn đang lưu trữ và chú ý đến những gì Jeffrey L Whitledge vừa nói), không bị ảnh hưởng bởi thiết kế đối tượng của bạn.
Các mẫu TPT, TPH và TPC là những cách bạn đi, như Brad Wilson đã đề cập. Nhưng vài lưu ý:
các lớp con kế thừa từ một lớp cơ sở có thể được coi là các thực thể yếu đối với định nghĩa lớp cơ sở trong cơ sở dữ liệu, có nghĩa là chúng phụ thuộc vào lớp cơ sở của chúng và không thể tồn tại mà không có nó. Tôi đã thấy số lần, các ID duy nhất được lưu trữ cho mỗi bảng con trong khi vẫn giữ FK cho bảng cha. Một FK là vừa đủ và thậm chí còn tốt hơn khi bật tầng cho phép xóa mối quan hệ FK giữa bảng con và bảng cơ sở.
Trong TPT, bằng cách chỉ xem các bản ghi bảng cơ sở, bạn không thể tìm thấy lớp con nào mà bản ghi đang biểu diễn. Điều này đôi khi cần thiết, khi bạn muốn tải một danh sách tất cả các bản ghi (không thực hiện select
trên mỗi bảng con). Một cách để xử lý việc này là có một cột biểu thị loại lớp con (tương tự như trường rowType trong TPH), do đó, trộn lẫn TPT và TPH bằng cách nào đó.
Giả sử chúng tôi muốn thiết kế một cơ sở dữ liệu chứa sơ đồ lớp hình dạng sau:
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;
}
Thiết kế cơ sở dữ liệu cho các lớp trên có thể như thế này:
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;
Có hai loại thừa kế chính mà bạn có thể thiết lập trong DB, bảng cho mỗi thực thể và bảng theo Phân cấp.
Bảng trên mỗi thực thể là nơi bạn có một bảng thực thể cơ sở có các thuộc tính chung của tất cả các lớp con. Sau đó, bạn có mỗi lớp con một bảng khác chỉ có các thuộc tính áp dụng cho lớp đó. Chúng được liên kết 1: 1 bởi PK của họ
Bảng trên mỗi hệ thống phân cấp là nơi tất cả các lớp chia sẻ một bảng và các thuộc tính tùy chọn là không thể. Họ cũng là một trường phân biệt đối xử là một số biểu thị loại mà hồ sơ hiện đang nắm giữ
SessionTypeID là phân biệt đối xử
Mục tiêu trên mỗi phân cấp nhanh hơn để truy vấn vì bạn không cần tham gia (chỉ có giá trị phân biệt đối xử), trong khi mục tiêu cho mỗi thực thể bạn cần thực hiện các phép nối phức tạp để phát hiện loại gì cũng như lấy lại tất cả dữ liệu của nó ..
Chỉnh sửa: Hình ảnh tôi hiển thị ở đây là ảnh chụp màn hình của một dự án tôi đang thực hiện. Hình ảnh Tài sản không đầy đủ, do đó, nó trống rỗng, nhưng chủ yếu là để hiển thị cách thiết lập của nó, chứ không phải những gì để đặt trong các bảng của bạn. Điều đó tùy thuộc vào bạn ;). Bảng phiên chứa thông tin phiên cộng tác ảo và có thể có một số loại phiên tùy thuộc vào loại cộng tác nào có liên quan.
Bạn sẽ bình thường hóa cơ sở dữ liệu của bạn và điều đó thực sự sẽ phản ánh sự kế thừa của bạn. Nó có thể có sự suy giảm hiệu suất, nhưng đó là cách nó được bình thường hóa. Bạn có thể sẽ phải sử dụng ý thức chung tốt để tìm sự cân bằng.
lặp lại câu trả lời chủ đề tương tự
trong ánh xạ OR, ánh xạ kế thừa vào một bảng cha trong đó các bảng cha và con sử dụng cùng một mã định danh
ví dụ
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 có mối quan hệ khóa ngoài với Object. Khi bạn tạo một hàng SubObject, trước tiên bạn phải tạo một hàng Object và sử dụng Id trong cả hai hàng
EDIT: nếu bạn đang tìm cách mô hình hóa hành vi, bạn sẽ cần một bảng Loại liệt kê các mối quan hệ thừa kế giữa các bảng và chỉ định tên tập hợp và tên lớp thực hiện hành vi của mỗi bảng
Có vẻ như quá mức cần thiết, nhưng tất cả phụ thuộc vào những gì bạn muốn sử dụng nó cho!
Sử dụng SQL ALchemy (Python ORM), bạn có thể thực hiện hai loại kế thừa.
Người mà tôi đã có kinh nghiệm là sử dụng bảng đơn và có một cột phân biệt đối xử. Chẳng hạn, cơ sở dữ liệu Sheep (không đùa!) Đã lưu trữ tất cả Sheep trong một bảng và Ram và Ewes được xử lý bằng cột giới tính trong bảng đó.
Vì vậy, bạn có thể truy vấn tất cả Cừu và lấy tất cả Cừu. Hoặc bạn chỉ có thể truy vấn bằng Ram và nó sẽ chỉ nhận được Ram. Bạn cũng có thể làm những việc như có một mối quan hệ chỉ có thể là Ram (tức là Sire of a Sheep), v.v.
Lưu ý rằng một số công cụ cơ sở dữ liệu đã cung cấp các cơ chế kế thừa thực sự giống như Postgres . Nhìn vào tài liệu .
Ví dụ: bạn sẽ truy vấn hệ thống Người / Nhân viên được mô tả trong phản hồi ở trên như sau:
/ * Điều này hiển thị tên của tất cả người hoặc nhân viên * / CHỌN tên đầu tiên từ người; / * Điều này chỉ hiển thị ngày bắt đầu của tất cả nhân viên * / CHỌN ngày bắt đầu từ nhân viên;
Trong đó là lựa chọn cơ sở dữ liệu của bạn, bạn không cần phải đặc biệt thông minh!