2011-01-16 33 views
17

Tôi đang làm việc trên trình chỉnh sửa cho phép người dùng tạo định nghĩa "đối tượng" trong thời gian thực. Một định nghĩa có thể chứa không hoặc nhiều thuộc tính. Thuộc tính có tên là một loại. Khi định nghĩa được tạo, người dùng có thể tạo một đối tượng của định nghĩa đó và đặt các giá trị thuộc tính của đối tượng đó.Giản đồ hỗ trợ các thuộc tính động

Vì vậy, bằng cách nhấp vào nút chuột, người dùng nên có nghĩa là. có thể tạo định nghĩa mới có tên là "Xe đạp" và thêm thuộc tính "Kích thước" của loại "Chữ số". Sau đó, một thuộc tính khác được gọi là "Tên" của loại "Văn bản", và sau đó một thuộc tính khác được gọi là "Giá" của loại "Chữ số". Khi đã xong, người dùng sẽ có thể tạo một vài đối tượng "Xe đạp" và điền vào các giá trị thuộc tính "Tên" và "Giá" của mỗi chiếc xe đạp.

Bây giờ, tôi đã thấy tính năng này trong một số sản phẩm phần mềm, vì vậy nó phải là một khái niệm nổi tiếng. Vấn đề của tôi bắt đầu khi tôi ngồi xuống và cố gắng đưa ra một lược đồ DB để hỗ trợ cấu trúc dữ liệu này, bởi vì tôi muốn các giá trị thuộc tính được lưu trữ bằng cách sử dụng các kiểu cột thích hợp. I E. một giá trị thuộc tính số được lưu trữ như, ví dụ, một INT trong cơ sở dữ liệu và một giá trị thuộc tính văn bản được lưu trữ như VARCHAR.

Trước tiên, tôi cần một bảng mà sẽ giữ tất cả các định nghĩa đối tượng của tôi:

Table obj_defs 

id | name  | 
---------------- 
1 | "Bicycle" | 
2 | "Book" | 

Sau đó, tôi cần một bảng để giữ những gì sắp xếp tài sản mỗi định nghĩa đối tượng nên có:

Table prop_defs 

id | obj_def_id | name  | type | 
------------------------------------ 
1 |   1 | "Size" | ? | 
2 |   1 | "Name" | ? | 
3 |   1 | "Price" | ? | 
4 |   2 | "Title" | ? | 
5 |   2 | "Author" | ? | 
6 |   2 | "ISBN" | ? | 

tôi cũng sẽ cần một bảng chứa từng đối tượng:

Table objects 

id | created | updated | 
------------------------------ 
1 | 2011-05-14 | 2011-06-15 | 
2 | 2011-05-14 | 2011-06-15 | 
3 | 2011-05-14 | 2011-06-15 | 

Cuối cùng, tôi cần một bảng có wi ll giữ giá trị tài sản thực tế của từng đối tượng, và một giải pháp là cho bảng này có một cột cho từng loại giá trị càng tốt, như thế này:

Table prop_vals 

id | prop_def_id | object_id | numeric | textual | boolean | 
------------------------------------------------------------ 
1 |   1 |   1 |  27 |   |   | 
2 |   2 |   1 |   | "Trek" |   | 
3 |   3 |   1 | 1249 |   |   | 
4 |   1 |   2 |  26 |   |   | 
5 |   2 |   2 |   | "GT" |   | 
6 |   3 |   2 |  159 |   |   | 
7 |   4 |   3 |   | "It" |   | 
8 |   5 |   3 |   | "King" |   | 
9 |   6 |   4 |  9 |   |   | 

Nếu tôi thực hiện sơ đồ này, những gì sẽ "loại" cột của bảng prop_defs giữ? Số nguyên rằng mỗi bản đồ đến một tên cột, varchars chỉ đơn giản là giữ tên cột? Bất kỳ khả năng nào khác? Một thủ tục được lưu trữ có giúp tôi ra khỏi đây theo một cách nào đó không? Và SQL sẽ tìm nạp thuộc tính "name" của đối tượng 2 trông như thế nào?

Trả lời

28

Bạn đang triển khai một cái gọi là mô hình Entity-Attribute-Value http://en.wikipedia.org/wiki/Entity-attribute-value_model.

Rất nhiều người sẽ nói đó là một ý tưởng tồi (thường tôi là một trong số đó) vì câu trả lời cho câu hỏi cuối cùng của bạn, "SQL tìm nạp ..." có xu hướng "dày lông và khó chịu, và gettting tồi tệ hơn. "

Những lời chỉ trích này có xu hướng giữ khi bạn cho phép người dùng bắt đầu lồng các đối tượng bên trong các đối tượng khác, nếu bạn không cho phép điều đó, tình hình sẽ vẫn quản lý được.

Đối với câu hỏi đầu tiên của bạn, cột "loại" của bảng prop_defs giữ ", mọi thứ sẽ đơn giản hơn nếu bạn có bảng loại và mô tả chứa {" số "," Số bất kỳ "}, {"văn bản", "Chuỗi"}, v.v. Giá trị đầu tiên là khóa chính. Sau đó, trong cột prop_def, cột "loại" của bạn là một khoá ngoại cho bảng đó và giữ giá trị "số", "văn bản", v.v. Một số sẽ cho bạn biết không chính xác để luôn sử dụng các phím số nguyên vì chúng JOIN nhanh hơn, nhưng nếu bạn sử dụng các giá trị " số "," văn bản ", v.v. bạn không phải JOIN và JOIN nhanh nhất là số bạn không làm.

Các truy vấn để lấy một giá trị duy nhất sẽ có một tuyên bố CASE:

SELECT case when pd.type = "numeric" then pv.numeric 
      when pd.type = "textual" then pv.textual 
      when pd.type = "boolean" then pv.boolean 
    from prov_vals pv 
    JOIN prop_defs pd ON pv.prop_def_id = pv.id 
WHERE pv.object_id = 2 
    AND pd.name = "Name" 
+0

Câu trả lời hay! Cảm ơn bạn rất nhiều :) –

+2

Điều gì sau đó sẽ là một giải pháp tốt hơn trong trường hợp EAV là một cái gì đó để tránh khi cần phải tổ các mặt hàng trình bày chính nó? – ChrisR

+0

Bây giờ với các giải pháp NoSQL như MongoDB, EAV cuối cùng cũng có thể chết. –

4

Bạn phải chấp nhận rằng cơ sở dữ liệu quan hệ là không giỏi cung cấp loại hình chức năng. Họ có thể cung cấp nó, nhưng không tốt ở đó. (Tôi hy vọng tôi sai). Các cơ sở dữ liệu quan hệ cho vay tốt hơn với các giao diện được định nghĩa, chứ không phải thay đổi các giao diện.

--Bảng AAV cung cấp cho trường động nhưng hút về hiệu suất. Sucks về lập chỉ mục. Và nó là phức tạp để truy vấn. Nó được thực hiện công việc trong nhiều tình huống, nhưng có thể sụp đổ trên các bảng lớn với rất nhiều người dùng nhấn vào hệ thống.

- Bảng "Thông thường" với một số cột giữ chỗ là OK để thực hiện, nhưng bạn nhận được tên cột không mô tả và bị giới hạn về số lượng cột bạn có thể "thêm". Ngoài ra nó không hỗ trợ tách loại phụ.

--Thông thường, bạn tạo/sửa đổi bảng vào thời gian phát triển, không chạy thời gian. Chúng ta có nên phân biệt đối xử với việc sửa đổi cơ sở dữ liệu trong thời gian chạy không? Co le không. Tạo các bảng mới, các khóa ngoài và các cột tại thời gian chạy có thể đạt được các đối tượng động thực, trong khi mang lại các lợi ích hiệu suất của các bảng "thông thường". Nhưng bạn sẽ phải truy vấn lược đồ của cơ sở dữ liệu, sau đó tự động tạo tất cả các truy vấn của bạn. Điều đó sẽ hút. Nó hoàn toàn sẽ phá vỡ khái niệm về các bảng như một giao diện.

Các vấn đề liên quan