2012-07-19 130 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提供了一种解决方法。不幸的是,所有这些都是不完美的:表结构的变化,丢失类型以查询映射超类,等等。