2013-04-16 13 views
11

Tôi đã có một lớp Java sau đó cũng là một thực thể Hibernate:java ngủ đông thực thể: cho phép thiết lập đối tượng có liên quan cả bởi id và đối tượng tự

@Entity 
@Table(name = "category") 
public class Category { 

    @ManyToOne 
    @JoinColumn(name="parent_id") 
    private Category parent; 

    public Category getParent() { 
     return parent; 
    } 

    public void setParent(Category parent) { 
     this.parent = parent; 
    } 

Phạm trù thể hiện một nút trong cây mục. Tôi đang triển khai một dịch vụ web cho phép các danh mục CRUD. Ví dụ, giao diện có khả năng tạo một nút cây danh mục và nó chuyển id danh mục làm tham số.

Tôi chỉ muốn tạo đối tượng Danh mục mới và lưu giữ nó vào cơ sở dữ liệu mà không cần tìm nạp đối tượng gốc. lớp nhà cung cấp dữ liệu của tôi trông như thế này:

public void createCategory(int parent_id, String name, CategoryType type) { 
    Category category = new Category(); 
    category.setName(name); 
    // category.setParent(?); <- I don't have this object here 
    // category.setParentId(id); <- but I do have the id 
    category.setType(type); 
    this.categoryDao.save(category); 
} 

Câu hỏi của tôi là: những gì tôi có thể làm gì để tạo ra một đối tượng loại mới với PARENT_ID thiết lập nếu giả sử tôi sẽ không gọi ngủ đông để lấy phụ huynh đối với tôi (điều này sẽ là ngu ngốc)? Tôi có thể cung cấp phương thức setParentId/getParentId cho lớp Danh mục không? Những chú thích ngủ đông nào nó có?

+0

Tại sao bạn không thử? Có, nó có thể sẽ hoạt động. – Magnilex

+0

@MagnusTengdahl Tôi không biết cách vẽ bản đồ chú thích ... – ducin

Trả lời

17

Hibernate cung cấp phương thức được gọi là (khá gây nhầm lẫn) Session.load() cho trường hợp này.

Session.load() trả về proxy lười với số nhận dạng đã cho mà không truy vấn cơ sở dữ liệu (nếu đối tượng có số nhận dạng đã cho đã được tải trong Session hiện tại, nó sẽ tự trả về một đối tượng).

Bạn có thể sử dụng proxy để khởi tạo mối quan hệ trong tổ chức của bạn đang được lưu:

category.setParent(session.load(Category.class, parent_id)); 

Lưu ý rằng mã này không kiểm tra sự tồn tại của Category với id cụ thể. Tuy nhiên, nếu bạn có ràng buộc khóa ngoài trong lược đồ DB, bạn sẽ nhận được một lỗi vi phạm ràng buộc khi id không hợp lệ được chuyển vào.

JPA tương đương với phương pháp này được gọi là EntityManager.getReference().

+0

Tôi có một vấn đề ở đây: thiết kế kiến ​​trúc của tôi giả sử tôi đang sử dụng BO/DAO (đối tượng kinh doanh/đối tượng truy cập dữ liệu).DAO là cấp độ ngủ đông và nó giữ phiên ngủ đông. BO (một trong đoạn mã thứ hai của tôi) thậm chí không biết rằng một thứ như phiên ngủ đông tồn tại. Nhưng - theo mã của bạn - tôi phải sử dụng 'session.load'. Tôi nên thay đổi gì trong kiến ​​trúc của mình? – ducin

+0

Nếu tôi muốn lớp BO thể loại của tôi là chung chung, có lẽ tôi nên cung cấp phương pháp 'setParentId' cho danh mục, gọi nó trong BO và xử lý nó ở cấp DAO - bạn nghĩ gì về điều đó? – ducin

+0

Tôi nghĩ rằng tùy chọn tốt nhất là thêm một phương thức tương ứng vào DAO của bạn, giống như 'Category toReference (long categoryId)'. – axtavt

-1

Bạn có thể xác định lười biếng init

@ManyToOne(fetch=FetchType.LAZY) 

đoán cột là nullable do đó, nó không phải là một vấn đề để tiết kiệm các loại mà không cần cha mẹ (root)

+0

Điều đó không trả lời được câu hỏi. Và mục tiêu chính xác là tạo danh mục với cha mẹ. –

1

Có thêm một giải pháp cho vấn đề - bằng cách sử dụng mặc định hàm tạo của thực thể bạn muốn tham chiếu và đặt id và phiên bản (nếu nó được phiên bản).

 Constructor<S> c = entityClass.getDeclaredConstructor(); 
     c.setAccessible(true); 

     S instance = c.newInstance(); 
     Fields.set(instance, "id", entityId.getId()); 
     Fields.set(instance, "version", entityId.getVersion()); 
     return instance; 

Chúng tôi có thể sử dụng cách tiếp cận này vì chúng tôi không sử dụng tải chậm nhưng thay vào đó có 'chế độ xem' của thực thể được sử dụng trên GUI. Điều đó cho phép chúng tôi thoát khỏi tất cả các kết nối Hibernate sử dụng để điền vào tất cả các mối quan hệ háo hức. Các khung nhìn luôn có id và phiên bản của thực thể. Do đó, chúng ta có thể điền vào các tham chiếu bằng cách tạo ra một đối tượng mà sẽ xuất hiện để Hibernate như không thoáng qua.

Tôi đã thử cả phương pháp này và phương pháp có session.load(). Cả hai đều làm việc tốt. Tôi thấy một số lợi thế trong cách tiếp cận của tôi như Hibernate sẽ không bị rò rỉ với proxy của nó ở nơi khác trong mã. Nếu không được sử dụng đúng cách, tôi sẽ chỉ nhận được NPE thay vì ngoại lệ 'no session bound to thread'.