PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Ánh xạ JPA nhiều hàng với ElementCollection

Đáng buồn thay, tôi nghĩ rằng sự khác biệt nhỏ mà bạn chỉ giữ một bảng là vấn đề ở đây.

Xem phần khai báo của PhoneId lớp (mà tôi muốn đề xuất tốt hơn nên được gọi là PhoneOwner hoặc cái gì đó tương tự):

@Entity
@Table(name="Phones")
public class PhoneId {

Khi bạn tuyên bố rằng một lớp là một thực thể được ánh xạ tới một bảng nhất định, bạn đang thực hiện một tập hợp các xác nhận, trong đó hai xác nhận là đặc biệt quan trọng ở đây. Thứ nhất, có một hàng trong bảng cho mỗi phiên bản của thực thể và ngược lại. Thứ hai, có một cột trong bảng cho mỗi trường vô hướng của thực thể và ngược lại. Cả hai điều này đều là trọng tâm của ý tưởng về ánh xạ quan hệ đối tượng.

Tuy nhiên, trong lược đồ của bạn, không có khẳng định nào trong số này được giữ nguyên. Trong dữ liệu bạn đã cung cấp:

OWNER_ID    TYPE      NUMBER
  1         home      792-0001
  1         work      494-1234
  2         work      892-0005

Có hai hàng tương ứng với thực thể có owner_id 1, vi phạm khẳng định đầu tiên. Có các cột TYPENUMBER không được ánh xạ tới các trường trong thực thể, vi phạm khẳng định thứ hai.

(Nói rõ hơn, không có gì sai khi bạn khai báo về Phone lớp học hoặc phones trường - chỉ PhoneId thực thể)

Do đó, khi nhà cung cấp JPA của bạn cố gắng chèn một bản sao của PhoneId vào cơ sở dữ liệu, nó gặp sự cố. Vì không có ánh xạ nào cho TYPENUMBER trong PhoneId , khi nó tạo SQL cho phần chèn, nó không bao gồm các giá trị cho chúng. Đây là lý do tại sao bạn gặp lỗi mà bạn thấy - nhà cung cấp ghi INSERT INTO Phones (owner_id) VALUES (?) , PostgreSQL được coi là INSERT INTO Phones (owner_id, type, number) VALUES (?, null, null) , bị từ chối.

Ngay cả khi bạn đã quản lý để chèn một hàng vào bảng này, sau đó bạn sẽ gặp rắc rối khi lấy một đối tượng từ nó. Giả sử bạn đã yêu cầu phiên bản của PhoneId với owner_id 1. Nhà cung cấp sẽ ghi số lượng SQL vào select * from Phones where owner_id = 1 và nó sẽ mong đợi rằng sẽ tìm thấy chính xác một hàng, hàng mà nó có thể ánh xạ tới một đối tượng. Nhưng nó sẽ tìm thấy hai hàng!

Tôi e rằng giải pháp là sử dụng hai bảng, một bảng cho PhoneId và một cho Phone . Bảng cho PhoneId sẽ rất đơn giản, nhưng nó cần thiết để vận hành chính xác bộ máy JPA.

Giả sử bạn đổi tên PhoneId tới PhoneOwner , các bảng cần có dạng:

create table PhoneOwner (
    owner_id integer primary key
)

create table Phone (
    owner_id integer not null references PhoneOwner,
    type varchar(255) not null,
    number varchar(255) not null,
    primary key (owner_id, number)
)

(Tôi đã tạo (owner_id, number) khóa chính cho Phone , với giả định rằng một chủ sở hữu có thể có nhiều hơn một số thuộc một loại nhất định, nhưng sẽ không bao giờ có một số được ghi dưới hai loại. Bạn có thể thích (owner_id, type) nếu điều đó phản ánh tốt hơn miền của bạn.)

Các thực thể sau đó là:

@Entity
@Table(name="PhoneOwner")
public class PhoneOwner {
    @Id
    @Column(name="owner_id")
    long id;

    @ElementCollection
    @CollectionTable(name = "Phone", joinColumns = @JoinColumn(name = "owner_id"))
    List<Phone> phones = new ArrayList<Phone>();
}

@Embeddable
class Phone {
    @Column(name="type", nullable = false)
    String type;
    @Column(name="number", nullable = false)
    String number;
}

Bây giờ, nếu bạn thực sự không muốn giới thiệu một bảng cho PhoneOwner , thì bạn có thể thoát ra khỏi nó bằng cách sử dụng một chế độ xem. Như thế này:

create view PhoneOwner as select distinct owner_id from Phone;

Theo như nhà cung cấp JPA có thể nói, đây là một bảng và nó sẽ hỗ trợ các truy vấn cần thực hiện để đọc dữ liệu.

Tuy nhiên, nó sẽ không hỗ trợ chèn. Nếu bạn cần thêm điện thoại cho chủ sở hữu hiện không có trong cơ sở dữ liệu, bạn cần phải quay lại và chèn một hàng trực tiếp vào Phone . Không đẹp lắm.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bộ đệm kế hoạch thực thi cho các hàm PL / pgSQL trong PostgreSQL

  2. Làm cách nào để tăng tốc độ chênh lệch giữa các bảng?

  3. Ngày hội nhà phát triển PostgreSQL ở Praha 2016

  4. Cách nhanh nhất để thực hiện truy vấn xóa trong bảng lớn trong PostgreSQL

  5. Chỉ mục để tìm một phần tử trong một mảng JSON