2010-04-01 11 views
7

Tôi đang phát triển một Ứng dụng Java Desktop và sử dụng JPA để kiên trì. Tôi đã là một vấn đề đề cập dưới đây:JPA - Vấn đề thiết kế thực thể

Tôi có hai thực thể:

  • Nước
  • Thành phố

Nước có các thuộc tính sau:

  • CountryName (PK)

City có các thuộc tính sau:

  • CityName

Bây giờ là có thể có hai thành phố cùng tên ở hai quốc gia khác nhau, PrimaryKey cho bảng thành phố trong datbase là một khóa chính tổng hợp gồm của CityNameCountryName.

Bây giờ câu hỏi của tôi là như thế nào để thực hiện các khóa chính của City như một Entity trong Java

@Entity 
    public class Country implements Serializable { 
     private String countryName; 

     @Id 
     public String getCountryName() { 
      return this.countryName; 
     } 
    } 

    @Entity 
    public class City implements Serializable { 
      private CityPK cityPK; 
      private Country country; 

      @EmbeddedId 
      public CityPK getCityPK() { 
       return this.cityPK; 
      } 
    } 


    @Embeddable 
    public class CityPK implements Serializable { 
     public String cityName; 
     public String countryName; 
    } 

Bây giờ như chúng ta biết rằng mối quan hệ Country-CityOneToMany và để hiển thị này mối quan hệ trong mã trên, tôi đã thêm một biến số country trong lớp City.

Nhưng sau đó chúng tôi có dữ liệu trùng lặp (countryName) được lưu trữ ở hai nơi trong đối tượng City lớp: một trong đối tượng country và khác trong đối tượng cityPK.

Nhưng mặt khác, cả hai đều cần thiết:

  • countryName trong cityPK đối tượng là cần thiết vì chúng tôi thực hiện khóa chính tổng hợp theo cách này.

  • countryName trong đối tượng country là cần thiết vì đây là cách tiêu chuẩn để hiển thị sự tương tác giữa các đối tượng.

Làm thế nào để có được xung quanh vấn đề này?

Trả lời

7

countryName trong CityPK nên được đánh dấu read-only sử dụng @Column(insertable = false, updatable = false) và cả countryName s nên được ánh xạ tới cùng một cột (sử dụng name tài sản):

@Entity 
    public class City implements Serializable { 
      @EmbeddedId 
      private CityPK cityPK; 

      @ManyToOne 
      @JoinColumn(name = "countryName") 
      private Country country; 
    } 


    @Embeddable 
    public class CityPK implements Serializable { 
     public String cityName; 

     @Column(name = "countryName", insertable = false, updatable = false) 
     public String countryName; 
    } 
+0

Đây có phải là cách tiêu chuẩn để xử lý loại vấn đề này không? Vấn đề này có phổ biến trong JPA không? –

+0

@ Yatendra: Vâng, đó là một cách tiêu chuẩn (nếu bạn không sử dụng khóa thay thế, như Peter gợi ý). – axtavt

3

IMO cách thích hợp để đối phó với các vấn đề như vậy sẽ để sử dụng ID nội bộ (thường là Long) được tạo thay vì khóa chính tự nhiên - điều này sẽ loại bỏ toàn bộ vấn đề. Tất nhiên, điều này đòi hỏi một sửa đổi của lược đồ DB của bạn, nhưng từ bài viết của bạn tôi giả định rằng điều này là có thể.

@Entity 
public class City implements Serializable { 
    private Long id; 

    private String name; 
    private Country country; 

    @Id 
    @GeneratedValue 
    @Column(name = "CITY_ID") 
    public Long getId() { 
     return this.id; 
    } 
    private void setId(Long id) { 
     this.id = id; 
    } 

    // more getters, setters and annotations 
} 
+0

Sau đó, tôi nghĩ rằng tôi không thể sử dụng 'id' trong phương thức equals cho bình đẳng. Chính xác? –

+0

@Yatendra Tại sao không? Hai thành phố có cùng tên nhưng quốc gia khác nhau phải có các ID khác nhau. Bạn chỉ cần đảm bảo rằng bạn không chèn cùng một thành phố của cùng một quốc gia hai lần vào bảng. Điều này có thể được thực thi bởi một kích hoạt DB, hoặc bởi một kẻ đánh chặn Hibernate. –

+0

Bạn không thể sử dụng 'id' trong' equals() 'vì' id' được tạo ra bởi cơ sở dữ liệu. Và sẽ không có sẵn cho đến khi đối tượng được tiếp tục tồn tại. Tham khảo 'Java Persistence with Hibernate' của Gavin King, xem phần thảo luận về khóa kinh doanh và khóa thay thế. – Ram