2008-10-20 33 views
26

Ai đó có thể giải thích cho tôi cách chú thích có liên quan đến Bất kỳ (@Any, @AnyMetaDef, @AnyMetaDefs@ManyToAny) hoạt động trong thực tế. Tôi có một thời gian khó khăn tìm kiếm bất kỳ tài liệu hữu ích (JavaDoc một mình không phải là rất hữu ích) về những điều này.Cách sử dụng Hibernate @ Bất kỳ chú thích nào có liên quan?

Do đó, tôi đã thu thập được rằng bằng cách nào đó, chúng cho phép tham chiếu đến các lớp trừu tượng và mở rộng. Nếu đây là trường hợp, tại sao không có chú thích @OneToAny? Và liệu 'bất kỳ' này có ám chỉ đến một 'bất kỳ', hay nhiều 'bất kỳ' nào không?

Ví dụ ngắn, thực tế và minh họa sẽ được đánh giá rất nhiều (không phải biên dịch).

Chỉnh sửa: nhiều như tôi muốn chấp nhận trả lời làm câu trả lời và cho tín dụng khi đến hạn, tôi tìm thấy cả câu trả lời của Smink và Sakana. Vì tôi không thể chấp nhận một số câu trả lời là câu trả lời, tôi rất tiếc sẽ không đánh dấu câu trả lời.

+1

Tôi muốn chỉ ra rằng thực tiễn này được coi là một mẫu chống SQL, theo sách Bill Karwin. – atorres

Trả lời

2

Bạn đã đọc the Hibernate Annotations documentation for @Any chưa? Đã không sử dụng một bản thân mình chưa, nhưng nó trông giống như một số cách mở rộng để xác định tài liệu tham khảo. Các liên kết bao gồm một ví dụ, mặc dù tôi không biết nếu đó là đủ để hiểu đầy đủ về khái niệm ...

22

Hope article này mang lại một số ánh sáng đến chủ đề:

Đôi khi chúng ta cần để ánh xạ một liên kết bất động sản với các loại khác nhau loại thực thể không có tổ chức tổ tiên chung là - do đó, một liên kết đa hình đơn giản không làm công việc .

Ví dụ, giả sử ba ứng dụng khác nhau quản lý thư viện phương tiện - ứng dụng đầu tiên quản lý việc mượn sách, DVD thứ hai và VHS thứ ba. Các ứng dụng không có điểm chung. Bây giờ chúng tôi muốn phát triển một ứng dụng mới quản lý tất cả ba loại phương tiện truyền thông và tái sử dụng các thực thể Sách, DVD và VHS cũ. Vì các lớp Sách, DVD và VHS đến từ các ứng dụng khác nhau nên chúng không có bất kỳ tổ tiên nào - tổ tiên chung là java.lang.Object. Tuy nhiên, chúng tôi muốn có một thực thể Mượn có thể tham chiếu đến bất kỳ loại phương tiện có thể nào.

Để giải quyết loại tham chiếu này, chúng tôi có thể sử dụng bất kỳ ánh xạ nào. ánh xạ này luôn bao gồm nhiều cột: một cột bao gồm loại thực thể mà thuộc tính được ánh xạ hiện tại đề cập đến và thực thể khác bao gồm danh tính của thực thể, ví dụ: nếu chúng tôi đề cập đến một cuốn sách, cột đầu tiên sẽ bao gồm điểm đánh dấu loại thực thể Sách và loại thứ hai sẽ bao gồm id của sách cụ thể.

@Entity 
@Table(name = "BORROW") 
public class Borrow{ 

    @Id 
    @GeneratedValue 
    private Long id; 

    @Any(metaColumn = @Column(name = "ITEM_TYPE")) 
    @AnyMetaDef(idType = "long", metaType = "string", 
      metaValues = { 
      @MetaValue(targetEntity = Book.class, value = "B"), 
      @MetaValue(targetEntity = VHS.class, value = "V"), 
      @MetaValue(targetEntity = DVD.class, value = "D") 
     }) 
    @JoinColumn(name="ITEM_ID") 
    private Object item; 

    ....... 
    public Object getItem() { 
     return item; 
    } 

    public void setItem(Object item) { 
     this.item = item; 
    } 

} 
19

Chú thích @Any định nghĩa sự liên kết đa hình với các lớp từ nhiều bảng. Kiểu ánh xạ này luôn yêu cầu nhiều hơn một cột. Cột đầu tiên giữ kiểu của thực thể liên kết. Các cột còn lại giữ số nhận dạng. Không thể chỉ định ràng buộc khoá ngoại cho loại liên kết này, do đó, điều này chắc chắn không có nghĩa là cách thông thường của các liên kết ánh xạ (đa hình). Bạn chỉ nên sử dụng này trong các trường hợp rất đặc biệt (ví dụ: nhật ký kiểm tra, dữ liệu phiên của người dùng, v.v.). Chú thích @Any mô tả cột chứa thông tin siêu dữ liệu. Để liên kết giá trị của thông tin siêu dữ liệu và loại thực thể thực, chú thích @AnyDef và @AnyDefs được sử dụng.

@Any(metaColumn = @Column(name = "property_type"), fetch=FetchType.EAGER) 
@AnyMetaDef(
    idType = "integer", 
    metaType = "string", 
    metaValues = { 
     @MetaValue(value = "S", targetEntity = StringProperty.class), 
     @MetaValue(value = "I", targetEntity = IntegerProperty.class) 
}) 
@JoinColumn(name = "property_id") 
public Property getMainProperty() { 
    return mainProperty; 
} 

idType đại diện cho loại thuộc tính định danh đối tượng mục tiêu và loại meta loại siêu dữ liệu (thường là Chuỗi). Lưu ý rằng @AnyDef có thể được tương tác và sử dụng lại. Bạn nên đặt nó làm siêu dữ liệu gói trong trường hợp này.

//on a package 
@AnyMetaDef(name="property" 
idType = "integer", 
metaType = "string", 
metaValues = { 
@MetaValue(value = "S", targetEntity = StringProperty.class), 
@MetaValue(value = "I", targetEntity = IntegerProperty.class) 
}) 
package org.hibernate.test.annotations.any; 
//in a class 
@Any(metaDef="property", metaColumn = @Column(name = "property_type"), fetch=FetchType.EAGER) 
@JoinColumn(name = "property_id") 
public Property getMainProperty() { 
    return mainProperty; 
} 

@ManyToAny cho phép liên kết đa hình với các lớp từ nhiều bảng. Loại ánh xạ này luôn yêu cầu nhiều hơn một cột. Cột đầu tiên giữ kiểu của thực thể liên kết. Các cột còn lại giữ số nhận dạng. Không thể chỉ định ràng buộc khoá ngoại cho loại liên kết này, vì vậy đây là hầu hết các chắc chắn không có nghĩa là cách thức thông thường của các liên kết ánh xạ (đa hình). Bạn chỉ nên sử dụng trường hợp này trong các trường hợp đặc biệt rất (ví dụ: nhật ký kiểm tra, dữ liệu phiên của người dùng, v.v.).

@ManyToAny(
metaColumn = @Column(name = "property_type")) 
@AnyMetaDef(
    idType = "integer", 
    metaType = "string", 
    metaValues = { 
@MetaValue(value = "S", targetEntity = StringProperty.class), 
@MetaValue(value = "I", targetEntity = IntegerProperty.class) }) 
@Cascade({ org.hibernate.annotations.CascadeType.ALL }) 
@JoinTable(name = "obj_properties", joinColumns = @JoinColumn(name = "obj_id"), 
    inverseJoinColumns = @JoinColumn(name = "property_id")) 
public List<Property> getGeneralProperties() { 

Src: Hibernate Annotations Reference Guide 3.4.0GA

Hy vọng nó sẽ giúp!

+1

Tôi biết điều này giống như 6 năm cuối, nhưng điều này cuối @ManyToAny bit lưu ass của tôi. Đã không nhìn thấy nó được đề cập bất cứ nơi nào và nó chỉ là về cách duy nhất để lập bản đồ một danh sách các đối tượng thừa kế từ một thực thể duy nhất. –

+0

Tôi ước tôi có thể thích nhiều hơn một lần –

1

Chú thích @Any định nghĩa liên kết đa hình với các lớp từ nhiều bảng, phải, nhưng các liên kết đa hình như đây là một mẫu chống SQL! Lý do chính là bạn không thể định nghĩa ràng buộc FK nếu một cột có thể tham chiếu đến nhiều hơn một bảng.

Một trong những giải pháp được Bill Karwin nêu trong cuốn sách của ông là tạo bảng giao cắt cho từng loại "Bất kỳ", thay vì sử dụng một cột có "loại" và sử dụng công cụ sửa đổi duy nhất để tránh trùng lặp. Giải pháp này có thể là một nỗi đau để làm việc với JPA.

Một giải pháp khác, cũng được đề xuất bởi Karwin, là tạo siêu kiểu cho các phần tử được kết nối. Lấy ví dụ về mượn sách, DVD hoặc VHS, bạn có thể tạo một Mục siêu loại và làm cho Sách, DVD và VHS kế thừa từ Mục, với chiến lược của bảng Đã tham gia. Mượn sau đó trỏ tới mục. Bằng cách này bạn hoàn toàn tránh được vấn đề FK. Tôi đã dịch cuốn sách ví dụ về JPA dưới đây:

@Entity 
@Table(name = "BORROW") 
public class Borrow{ 
//... id, ... 
@ManyToOne Item item; 
//... 
} 

@Entity 
@Table(name = "ITEMS") 
@Inheritance(strategy=JOINED) 
public class Item{ 
    // id, .... 
    // you can add a reverse OneToMany here to borrow. 
} 

@Entity 
@Table(name = "BOOKS")  
public class Book extends Item { 
    // book attributes 
} 

@Entity 
@Table(name = "VHS")  
public class VHS extends Item { 
    // VHSattributes 
} 

@Entity 
@Table(name = "DVD")  
public class DVD extends Item { 
    // DVD attributes 
} 
Các vấn đề liên quan