2012-04-15 19 views
6

Tôi đang mất mát ở đây, và có lẽ đó là điều hiển nhiên vì chuyên môn Hibernate của tôi yếu hơn các khu vực khác.Hibernate hoán đổi lớp nhúng để di chuyển dữ liệu hiện có

Trong mã cũ có một lớp Hibernate @EntityFoo. Một trong những thuộc tính của nó là thế này:

private OldBar bar = new OldBar(); 

OldBar là một lớp @Embeddable có sử dụng một cột duy nhất, foobar:

@Embeddable 
public class OldBar { 

    private String fooBar; 

    @Column(length = 10, nullable = false) 
    private String getFooBar() { 
    return fooBar; 
    } 

    @SuppressWarnings("unused") 
    private void setFooBar(String fooBar) { 
    this.fooBar = fooBar; 
    } 
} 

Vấn đề gốc là tôi cần phải làm một cái gì đó với OldBar.fooBar, nhưng thiết kế ban đầu có những hạn chế và có lĩnh vực này riêng tư, ngăn cản tôi phân lớp nó, vì vậy tôi phải tạo ra một lớp khác, NewBar, để thay thế một trường khác và truy cập vào trường riêng. Tôi nghĩ rằng kể từ khi NewBar cũng là Embeddable và có cùng @Column định, tôi chỉ có thể trao đổi trên lĩnh vực này trong lớp Foo:

private NewBar bar = new NewBar(); 

tôi muốn làm điều này bởi vì tôi có dữ liệu hiện có trong cột foobar, và Tôi muốn minh bạch sử dụng dữ liệu này với NewBar thay vì OldBar.

Thông qua nhật ký theo dõi Tôi đã thấy rằng Foo() được tạo, với phiên bản mặc định là NewBar(), như người ta mong đợi, khi hàm tạo được gọi. Tuy nhiên, do mã thời gian gọi Foo.getBar(), vì một số lý do, barnull! Tôi giả sử Hibernate được thiết lập nó để null vì lý do nào đó --- nhưng tại sao Hibernate không đọc dữ liệu từ cột foobar và tạo một thể hiện của NewBar? Tại sao nó hoạt động trở lại khi tôi đặt OldBar trở lại tại vị trí của NewBar? Chắc chắn không có gì trong cơ sở dữ liệu chính nó nói rằng các lớp học @Embeddable được ánh xạ tới cột, là có?

Cập nhật: Điều này trở nên lạ và lạ. Đôi khi tôi sẽ để mã qua đêm, và ngày hôm sau nó hoạt động! Hoặc ngày hôm sau nó không hoạt động! Bây giờ nó không hoạt động (nghĩa là, thuộc tính foobar được đặt thành null thay vì giá trị trong cơ sở dữ liệu), vì vậy tôi đã tạo lớp ExactCopyOfOldBar và đặt nó ở vị trí OldBar. Nó hoạt động tốt! Vì vậy, tôi chuyển về NewBar --- chỉ hoàn tác các thay đổi tạm thời của tôi. Nó vẫn hoạt động, khi nó chưa từng xảy ra! Có một số loại bộ nhớ cache nơi Hibernate serializes giá trị và không nhận được chúng từ cơ sở dữ liệu? Điều này rất kỳ quặc.

Cập nhật: Bây giờ tôi không còn có thể nhận được NewBar để làm việc. Tôi tạo ra OtherBar, về cơ bản giống với NewBar ngoại trừ nó có tên khác, và tôi cắm nó vào và nó hoạt động, đọc chính xác chuỗi được nhúng. Tôi chuyển trở lại thành NewBar và tôi lại nhận được null. Chuyện gì vậy?

Lưu ý rằng Foo đang được nạp thông qua net.databinder.auth.hib.AuthDataApplication.getUser(String username), mà đơn giản là đủ:

return (DataUser) Databinder.getHibernateSession().createCriteria(getUserClass()) 
    .add(Restrictions.eq("username", username)).uniqueResult(); 

tôi đã xác minh hơn và hơn nữa rằng Foo (người dùng) bảng có một hàng duy nhất với các dữ liệu chính xác, và quan trọng nhất là trường foobar có dữ liệu. Tại sao Hibernate trả lại cho tôi một số Foo với một trường nullfoobar? Tại sao chỉ cần chuyển đổi từ NewBar sang OtherBar làm cho nó bắt đầu hoạt động trở lại? Tại sao nó hoạt động cả ngày và sau đó ngừng làm việc sau khi tôi đã để nó qua đêm?

+0

Tôi giả định điều này là đúng, nhưng bạn không nói điều đó: Có phải 'Foo.bar' được đánh dấu là' @ Nhúng 'không? –

+0

@Tim Pote: Trên thực tế, đủ kỳ lạ, trong mã di sản ban đầu (đang hoạt động), nó được _not_ đánh dấu là '@ Embedded'. Tôi đã thử nó có và không có '@ Embedded' khi tôi thay đổi hình thức' OldBar' thành 'NewBar', và nó đã không tạo sự khác biệt. –

+0

@Tim Pote: Tôi đã học được từ Hibernate [documentation] (http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/) rằng "... nếu loại thuộc tính được chú thích là @Embeddable, nó được ánh xạ dưới dạng @Embedded, "về mặt kỹ thuật, phần' @ Embedded' là tùy chọn. –

Trả lời

1

Đây có thể là câu trả lời; Tôi sẽ phải chờ vài ngày để xem nó có thực sự khắc phục được vấn đề không. Thực ra có hai phần.

Trước tiên, để tiết lộ đầy đủ, lớp NewBar của tôi thực sự là một phân lớp của AbstractBar. Cuối cùng tôi muốn có các loại thanh có thể nhúng khác nhau, vì vậy tôi đặt @Embeddable ở mức AbstractBar, không phải ở cấp NewBar và đặt trường foobar riêng ở mức AbstractBar. Điều buồn cười là, điều này làm việc một số thời gian. Và như tôi đã đề cập, đôi khi tôi sẽ trở lại vào ngày hôm sau và Hibernate sẽ không tải trường foobar. Tôi không hiểu tại sao nó không phải là làm việc tất cả các thời gian hoặc làm việc không có thời gian.

Thứ hai, khi tôi đã cố gắng để thoát khỏi hệ thống cấp bậc này để loại bỏ một nguồn của vấn đề, tôi lồng việc AbstractBarNewBar nhưng quên mang theo các @Embeddable lên AbstractBar-NewBar, vì vậy Hibernate không thấy đó là một lớp có thể nhúng và không biết cách tải một chuỗi vào trường NewBar mà không có chỉ định @Embeddable. Đây là lý do tại sao OtherBar (với chú thích @Embeddable) hoạt động, nhưng không phải là NewBar (không có chú thích @Embeddable). Điều này tôi hiểu rất nhiều. Tại sao Hibernate không cảnh báo tôi rằng nó không thể tìm ra cách để tải một lĩnh vực, tôi không biết.

Vì vậy, để tóm tắt, Hibernate sẽ không tải trường có thể nhúng nếu bạn đã để lại chú thích @Embeddable khỏi lớp học. Đối với vấn đề ban đầu, tôi chỉ có thể đoán rằng @Embeddable là flaky khi cố gắng sử dụng nó trên một hệ thống phân cấp lớp, và rằng bạn tốt nhất để giữ tất cả các lĩnh vực nhúng của bạn ở một cấp trong lớp nhúng. Tôi hy vọng đó là vấn đề. Chúng tôi sẽ xem liệu nó có tiếp tục hoạt động vào ngày mai hay không.