2012-07-19 133 views
0

當我嘗試使用註釋設置我的模式時,我遇到了一些Hibernate的令人沮喪的行爲。假設我有一個與其他幾種類型具有一對多關係的實體。例如:JPA/Hibernate註釋不理解繼承?

@Entity 
@Table(name = "clubs") 
public class Club { 
    private long id; 
    private String name; 
    //... 

    private Collection<ClubLocation> locations; 

    public Club() { 
     this.name = null; 
     //... 

     this.locations = Collections.emptyList(); 
    } 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 

    @Column(nullable = false) 
    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 

    @OneToMany(mappedBy = "club") 
    public Collection<ClubLocation> getLocations() { 
     return locations; 
    } 
    public void setLocations(Collection<ClubLocation> locations) { 
     this.locations = locations; 
    } 
} 

現在,正如我所說,我想與其他一些實體的這個實體相關聯,因此它似乎是一個好主意來定義管理的關係回到Club,這樣一個超實體我不不需要在每個關聯的類中設置關係。我做到這一點使用:

@Entity 
@Table(name = "clubItems") 
@Inheritance(strategy = InheritanceType.JOINED) 
public class ClubItem { 
    protected Club club; 

    public ClubItem() { 
     this.club = null; 
    } 

    @ManyToOne(optional = false) 
    public Club getClub() { 
     return club; 
    } 
    public void setClub(Club club) { 
     this.club = club; 
    } 
} 

然後,我繼承了該類像:

@Entity 
@Table(name = "clubLocations") 
public class ClubLocation extends ClubItem { 
    private String title; 
    //... 

    public ClubLocation() { 
     this.title = null; 
     //... 
    } 

    @Column(nullable = false) 
    public String getTitle() { 
     return title; 
    } 
    public void setTitle(String title) { 
     this.title = title; 
    } 
} 

一切似乎都很好,只是當我嘗試運行,然後休眠與爆炸:

org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: ClubLocation.club in Club.locations 
[WARNING] [talledLocalContainer] at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:543) 
[WARNING] [talledLocalContainer] at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:508) 
[WARNING] [talledLocalContainer] at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:43) 
[WARNING] [talledLocalContainer] at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1127) 
[WARNING] [talledLocalContainer] at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:296) 
[WARNING] [talledLocalContainer] at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1112) 
[WARNING] [talledLocalContainer] at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1233) 
[WARNING] [talledLocalContainer] at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:154) 
[WARNING] [talledLocalContainer] at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:869) 
[WARNING] [talledLocalContainer] at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:183) 
[WARNING] [talledLocalContainer] at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:240) 
[WARNING] [talledLocalContainer] at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:120) 
[WARNING] [talledLocalContainer] at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83) 
[WARNING] [talledLocalContainer] at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:60) 

令人沮喪的是,如果我複製了ClubLocation類中的club屬性的getter和setter聲明,一切都很好。具體來說,它的工作原理髮現,如果我補充一下:

@Override 
@ManyToOne(optional = false) 
public Club getClub() { 
    return super.getClub(); 
} 
public void setClub(Club club) { 
    super.setClub(club); 
} 

...到ClubLocation類。但這沒有意義,因爲它所做的只是委託給超類。

Hibernate只是不夠複雜,無法處理繼承的映射字段,而沒有在子類中重新聲明getter/setter?如果Hibernate可以更優雅地處理這種情況,那麼需要如何設置/我做錯了什麼?

回答

1

我在項目中有類似的設置。我認爲,一個簡單而更多或更少的很好的辦法來解決,這是改變

private Collection<ClubLocation> locations; 

private Collection<ClubItem> items; 

(以及相關的getter,setter方法,太)。這樣它肯定有效。

如果您爲了方便的原因需要Club中的getLocations方法,您可以自由創建該方法。如果您確定,那些項目將只包含位置,您可以按原樣返回集合,否則您需要使用Java代碼進行過濾。

一個缺點是,如果項目也包含非位置元素,則Java中的過濾需要內存和CPU,因此它可能很慢。

1

談到JPA,你的映射是完全有效的。另外,例如在EclipseLink中,它的工作原樣。這是Hibernate實現中的問題。

This blog post提供了一種解決方法。不幸的是,所有這些都是不完美的:表結構的變化,丟失類型以查詢映射超類,等等。