2

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

@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 方法(它查找主键)传递一个“Article”对象,Hibernate 会抛出一个异常。

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

DB表结构:

表“文章”(ID,短文本)

表“供应商”(ID、名称)

表“采购”(articleID、supplierID、price)

我必须更改什么才能通过相应的“物品”对象找到“采购”记录?

4

2 回答 2

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;

请注意,我为 ID 使用了特定于休眠的生成器。您的 JPA 提供程序可能会有所不同。

于 2013-04-09T11:36:57.593 回答
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]生成标识符: component[article,supplier]{article=de.willms.spring.myerp.model.Article#1, supplier=de.willms.spring.myerp.model.Supplier#1},使用策略:org .hibernate.id.CompositeNestedGeneratedValueGenerator

...(冲洗)...

[调试] 列出实体:... de.willms.spring.myerp.model.Procurement{price=2.5, deliveryTime=10, procid=component[article,supplier]{article=de.willms.spring.myerp.model.文章#1,供应商=de.willms.spring.myerp.model.Supplier#1},价格单位=$}

然而,遗憾的是 JpaRepository 不能注入 find() 方法存根,只涉及主键的一部分。它是“无法根据路径解析属性”。欢迎您发表评论!

于 2013-04-09T19:39:16.693 回答