2013-04-09 24 views
2

我的实体有两个外键,其中一个是主键。我在JPA Wiki中读到,如果孩子的(采购)主键与父母的(文章)主键相同,则建立@OneToOne关系。Hibernate寻找错误的主键

@SuppressWarnings("serial") 
@Entity 
public class Procurement implements Serializable { 

    @Id 
    @OneToOne 
    // the child's primary key is the same as the parent 
    @JoinColumn(name = "articleId", referencedColumnName = "id") 
    private Article article; 

    @OneToOne 
    @JoinColumn(name = "supplierId", referencedColumnName = "id") 
    private Supplier supplier; 

遵循这一标准的做法,在JpaRepository应该是这样的:

@Repository 
public interface IProcurementRepository extends 
     JpaRepository<Procurement, Article> 

但是,如果我要拨打的findOne-方法(查找主键)提供的“条”对象,Hibernate会抛出一个异常。

org.hibernate.TypeMismatchException:提供了错误类型的ID为 类de.willms.spring.myerp.model.Procurement。预计:类 de.willms.spring.myerp.model.Procurement,得到了类 de.willms.spring.myerp.model.Article

数据库表结构:

表“的文章“(ID,shortText)

表 ”供应商“(ID,姓名)

表 ”采购“(条款ArticleID,供应商ID,价格)

我需要更改哪些内容才能找到相应的“Article”对象的“采购”记录?

+0

你的问题是有点混乱。你说**采购**是孩子,**第**条是父母,但采购不是从条款延伸。而且这是一个有点怪异,你有两个**标识**和** ** OneToOne注解的同时东西。 ** Id **表示一个数据列(或者如果使用复合键则为列)而** OneToOne **实际上是两个表之间的关系。你能否提供你的数据库表结构来让人们帮助你? – spiritwalker 2013-04-09 09:02:25

回答

1

最后,我在Hibernate中找到了一个特殊的函数(令人惊讶,但在文档中难以理解)导致了一个解决方案。

只要主键由多个列组成,或者就像我的情况一样,与其他表相关,就必须编写一个特殊的ID类。

@Embeddable  
public class Procurement_ID implements Serializable { 

    /** 
    * This attribute establishes the 1:1 connection to a record in the 
    * "article" table. The column "articleId" is a foreign key to the column 
    * "id" in the {@link Article} entity. (Warning: This is Hibernate 
    * specific!) 
    */ 
    @OneToOne 
    @JoinColumn(name = "articleId", referencedColumnName = "id") 
    private Article article; 

    /** 
    * This attribute establishes the 1:1 connection to a record in the table 
    * "supplier". The column "supplierId" is a foreign key to the column "id" 
    * in the {@link Supplier} entity. (Warning: This is Hibernate specific!) 
    */ 
    @OneToOne 
    @JoinColumn(name = "supplierId", referencedColumnName = "id") 
    private Supplier supplier; 

(由于更“归一化”的数据模型,我切换到复合主键。)

由于@Embeddable注释的,该ID可以被注射到实体类。

@Entity 
public class Procurement implements Serializable { 

    /** 
    * The composite primary key of the underlying table is defined in the 
    * {@link Procurement_ID} class. 
    */ 
    @EmbeddedId 
    private Procurement_ID procid; 

跟我使用这种方法时,Hibernate插入正外键检查一个新的记录:

[DEBUG] 生成的标识:成分[文章,供应商] {文章= de.willms .spring.myerp.model.Article#1,supplier = de.willms.spring.myerp.model.Supplier#1},using strategy:org.hibernate.id。CompositeNestedGeneratedValueGenerator

...(Flusing)...

[调试]清单实体:... de.willms.spring.myerp.model.Procurement {价格= 2.5,交货期= 10, procid = component [article,supplier] {article = de.willms.spring.myerp.model.Article#1, supplier = de.willms.spring.myerp.model.Supplier#1},priceUnit = $}

然而,很可惜的是,JpaRepository不能注入查找() - 方法存根concering古板的只是其中的一部分ary键。它“无法解析路径上的属性”。欢迎您发表评论!

1

您仍然必须使用int或long类型的id。区别在于,您不得不使用@JoinColumn加入@PrimaryKeyJoinColumn。你的课应该是这样的。

@SuppressWarnings("serial") 
@Entity 
public class Procurement implements Serializable { 

    @Id 
    @GeneratedValue(generator = "articleForeignGenerator") 
    /* Hibernate-specific generator needed for shared primary key */ 
    @GenericGenerator(name = "articleForeignGenerator", strategy = "foreign", parameters = @Parameter(name = "property", value = "article")) 
    @Column(name = "articleId") 
    private int articleId; 

    @OneToOne 
    // the child's primary key is the same as the parent 
    @PrimaryKeyJoinColumn 
    private Article article; 

    @OneToOne 
    @JoinColumn(name = "supplierId", referencedColumnName = "id") 
    private Supplier supplier; 

请注意,我使用特定于hibernate的生成器生成ID。您的JPA提供商可能会有所不同。

+0

很抱歉,但你的解决方案会导致另一个异常: “org.hibernate.id.IdentifierGenerationException:试图从空一到一个属性[de.willms.spring.myerp.model.Procurement.article]分配ID”。我希望在Hibernate文档中找到一些方法。 – PWillms 2013-04-09 14:32:39

+0

@PWillms您确定每次采购都有一篇文章吗? – WilQu 2013-04-09 14:35:57

+0

是的,从一元级别看到,我想存储有关现有项目的采购数据。具体记录应该连接到供应商记录。 – PWillms 2013-04-09 15:07:03