2013-06-17 16 views
7

Tôi đang gặp sự cố với tải chậm không hoạt động khi sử dụng bản đồ được thu thập bằng bộ sưu tập. Tôi tìm thấy bài viết tuyệt vời này mà dường như để sửa chữa các vấn đềTải xuống lười biếng Hibernate để đảo ngược một đến một cách giải quyết - cách thức hoạt động của tính năng này?

http://justonjava.blogspot.co.uk/2010/09/lazy-one-to-one-and-one-to-many.html

Một điều tôi không hiểu là như thế nào workaround sử dụng FieldHandled hoạt động. Bất cứ ai có thể giúp tôi hiểu điều này? Mã được đề cập bên dưới (được sao chép từ ví dụ trên liên kết):

@Entity 
public class Animal implements FieldHandled { 
    private Person owner; 
    private FieldHandler fieldHandler; 

    @OneToOne(fetch = FetchType.LAZY, optional = true, mappedBy = "animal") 
    @LazyToOne(LazyToOneOption.NO_PROXY) 
    public Person getOwner() { 
    if (fieldHandler != null) { 
     return (Person) fieldHandler.readObject(this, "owner", owner); 
    } 
    return owner; 
    } 

    public void setOwner(Person owner) { 
    if (fieldHandler != null) { 
     this.owner = fieldHandler.writeObject(this, "owner", this.owner, owner); 
     return; 
    } 
    this.owner = owner; 
    } 

    public FieldHandler getFieldHandler() { 
    return fieldHandler; 
    } 

    public void setFieldHandler(FieldHandler fieldHandler) { 
    this.fieldHandler = fieldHandler; 
    } 
} 

Tôi đang thiếu gì? Có lẽ tôi không biết đủ về vòng đời của hibernate ở đây? Tôi rất vui khi được điều tra nhưng bất cứ ai cũng có thể cho tôi một số gợi ý.

Xin cảm ơn trước.

EDIT

Tôi đẩy qua rất nhiều thay đổi vì vậy rất nhiều các đơn vị của tôi thực hiện FieldHandled nhưng sau đó phát hiện ra một số bài kiểm tra của tôi đã thất bại. Tôi bơm ra SQL và có một số điều kỳ lạ mà các câu lệnh SQL đã xảy ra theo các thứ tự khác nhau nếu giao diện này được thực hiện chỉ với những phương thức này được thiết lập.

public FieldHandler getFieldHandler() { 
    return fieldHandler; 
    } 

    public void setFieldHandler(FieldHandler fieldHandler) { 
    this.fieldHandler = fieldHandler; 
    } 

Điều này đã khiến các kiểm tra thất bại vì mọi thứ không hoàn toàn chính xác khi tôi đang khẳng định. Điều này làm tăng hiểu biết sai lệch của tôi về biến FieldHandler này.

Trả lời

9

Mã sau đây yêu cầu Hibernate sử dụng trình xử lý chặn thay vì proxy.

@LazyToOne(LazyToOneOption.NO_PROXY) 

From javadoc:

trả lại đối tượng thực nạp khi một tài liệu tham khảo được yêu cầu (tăng cường Bytecode là bắt buộc đối với tùy chọn này, rơi trở lại PROXY nếu lớp không được nâng cao)

Như có thể thấy, cần thiết phải mã hóa bytecode trước khi sử dụng. 'Lớp kiên trì được tăng cường' sau khi bytecode 'của nó được thiết kế'.

Ý tưởng là để đánh lừa Hibernate rằng lớp thực thể mà chúng tôi muốn sử dụng đã đã instrumented

Instrumentation nhiệm vụ được gọi sau khi mã được biên dịch. Instrumented entity extends FieldHandled. FieldHandled là một 'Giao diện được giới thiệu cho lớp nâng cao'

Hibernate xác minh thực thể tại thời gian chạy và đi đến kết luận rằng lớp học đã được cải tiến đó là lý do tại sao nó sử dụng đối tượng thực thay vì proxy và isn't loading related entity object as it normally did.

Edit:

Cho phép có một cái nhìn dưới mui xe:

  1. AnnotationBinder handlesNO_PROXY tùy chọn

    if (lazy != null) { 
        toOne.setLazy(!(lazy.value() == LazyToOneOption.FALSE)); 
        toOne.setUnwrapProxy((lazy.value() == LazyToOneOption.NO_PROXY)); 
    } 
    
  2. Cả org.hibernate.mapping.ManyToOneorg.hibernate.mapping.OneToOne là lớp con của org.hibernate.mapping.ToOne. ToOne#isUnwrapProxy() chỉ sử dụng là trong #getType:...

    getMappings() getTypeResolver() getTypeFactory() oneToOne (

  3. Cả ManyToOneTypeOneToOneType là lớp con của EntityType và chỉ sử dụng 'EntityType # unwrapProxy' là trong EntityType#resolveIdentifier(Serializable, SessionImplementor)

    boolean isProxyUnwrapEnabled = unwrapProxy && 
         session.getFactory() 
           .getEntityPersister(getAssociatedEntityName()) 
           .isInstrumented(); 
    
  4. Dưới đây là dự kiến ​​hệ thống phân cấp gọi: AbstractEntityPersister#isInstrumented() ->EntityMetamodel#isInstrumented() ->EntityInstrumentationMetadata#isInstrumented() -> vv và cuối cùng BytecodeProviderImpl.EntityInstrumentationMetadataImpl.EntityInstrumentationMetadataImpl()

    this.isInstrumented = FieldHandled.class.isAssignableFrom(entityClass); 
    

Đó là lý do tại sao nó yêu cầu một trong hai công cụ mã (ví dụ với InstrumentTask) hoặc thực hiện FieldHandled.


Để làm dài câu chuyện, bạn có thể xem EntityType#resolveIdentifier(Serializable, SessionImplementor). That's the reason why second object is not loaded even if it's nullable.

+0

Cảm ơn @lifus Đó có vẻ như nó có tất cả thông tin HTE tôi cần . Tôi sẽ trải qua điều này. Từ những gì tôi thấy bạn nói mặc dù Im vẫn không chắc chắn lý do tại sao tôi đã nhận được SQL chạy theo một thứ tự khác nhau. Tôi có thể phải điều tra thêm một số ... – RNJ

+0

cố gắng trao cho bạn tiền thưởng nhưng tôi đang sử dụng thiết bị di động. nếu tôi không thể hình dung ra bạn sẽ tự động nhận được nó khi nó hết hạn sớm. cảm ơn vì câu trả lời – RNJ

4

Giao diện FieldHandled đã được thay thế bằng giao diện PersistentAttributeInterceptable trong Hibernate 5. Bạn có thể đạt được kết quả tương tự bằng cách thực hiện giao diện mới này:

@Entity 
public class Animal implements PersistentAttributeInterceptable { 
    private Person owner; 
    private PersistentAttributeInterceptor interceptor; 

    @OneToOne(fetch = FetchType.LAZY, optional = true, mappedBy = "animal") 
    @LazyToOne(LazyToOneOption.NO_PROXY) 
    public Person getOwner() { 
     if (interceptor != null) { 
      return (Person) interceptor.readObject(this, "owner", owner); 
     } 
     return owner; 
    } 

    public void setOwner(Person owner) { 
     if (interceptor != null) { 
      this.owner = interceptor.writeObject(this, "owner", this.owner, owner); 
      return; 
     } 
     this.owner = owner; 
    } 

    @Override 
    public PersistentAttributeInterceptor $$_hibernate_getInterceptor() { 
     return interceptor; 
    } 

    @Override 
    public void $$_hibernate_setInterceptor(PersistentAttributeInterceptor interceptor) { 
     this.interceptor = interceptor; 
    } 
} 
Các vấn đề liên quan