【问题标题】:Hibernate MappingException: Foreign key must have same number of columns as the referenced primary keyHibernate MappingException:外键必须与引用的主键具有相同的列数
【发布时间】:2024-01-10 22:33:01
【问题描述】:

我有这个实体,叫做 FatRabbitCarrot:

@Entity
public class FatRabbitCarrot {
    private Long id;
    private FatRabbit fatRabbit;
    private Carrot carrot;

@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

@ManyToOne
@JoinColumn(name = "fatRabbit_id", foreignKey = @ForeignKey(name = "FK_FatRabbitCarrot_fatRabbit"))
public FatRabbit getFatRabbit() {
    return fatRabbit;
}

public void setFatRabbit(FatRabbit fatRabbit) {
    this.fatRabbit = fatRabbit;
}

@ManyToOne
@JoinColumn(name = "carrot_id", foreignKey = @ForeignKey(name = "FK_FatRabbitCarrot_carrot"))
public Carrot getCarrot() {
    return carrot;
}

public void setCarrot(Carrot carrot) {
    this.carrot = carrot;
}
}

而且它有效。现在上面的类已经替换了字段名,但是结构和我们的仓库一样。

然后我尝试添加一个新实体,该实体具有上述类的外键。我们称这个类为 NutToffee。 FatRabbitCarrot 与这个新实体具有 OneToMany 关系,而实体本身应该具有 ManyToOne 关系:

@Entity
public class NutToffee {

private Long id;
private String text;
private FatRabbitCarrot fatRabbitCarrot;

@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
    return id;
}

public void setId(Long id){
    this.id = id;
}

@Basic
@Column(name = "text")
public String getText() {
    return text;
}

public void setText(String text) {
    this.text = text;
}

@ManyToOne
@JoinColumn(name="fatRabbitCarrot_id", foreignKey = @ForeignKey(name = "FK_NutToffee_fatRabbitCarrot"))
public FatRabbitCarrot getFatRabbitCarrot() {
    return fatRabbitCarrot;
}

public void setFatRabbitCarrot(FatRabbitCarrot fatRabbitCarrot) {
    this.fatRabbitCarrot = fatRabbitCarrot;
}
}

现在这对我来说似乎是一个有效的课程。但它看起来不像。我们正在使用 Java 8、Hibernate JPA 2.1、Java EE 7 和 gradle 来构建我们想要部署的工件。我们尝试将其部署在 Wildfly 10 应用服务器上,但出现以下错误:

[2019-07-08 03:53:45,441] Artifact Gradle : com.solveralynx.wildrunner : fatties.war: java.lang.Exception: {"WFLYCTL0080: Failed services" => {"jboss.persistenceunit.\"fatties.war#FatUnit\"" => "org.jboss.msc.service.StartException in service jboss.persistenceunit.\"fatties.war#FatUnit\": org.hibernate.MappingException: Foreign key (FK_NutToffee_fatRabbitCarrot:NutToffee [fatRabbitCarrot_id])) must have same number of columns as the referenced primary key (FatRabbitCarrot [fatRabbit_id,carrot_id])
Caused by: org.hibernate.MappingException: Foreign key (FK_NutToffee_fatRabbitCarrot:NutToffee [fatRabbitCarrot_id])) must have same number of columns as the referenced primary key (FatRabbitCarrot [fatRabbit_id,carrot_id])"},"WFLYCTL0412: Required services that are not installed:" => ["jboss.persistenceunit.\"fatties.war#FatUnit\""],"WFLYCTL0180: Services with missing/unavailable dependencies" => undefined}

据我了解,Hibernate 找到了 FatRabbitCarrot 的复合主键?即使我们从未定义过一个?它似乎选择了一个假主键,它使用了来自实体 FatRabbitCarrot 的两个外键。

至于我的测试。我相信这是一个休眠问题。无论数据库状态如何,我总是会收到此错误。我在连接实体的 getter 上使用各种参数进行了测试,但没有成功。如果我同时删除新的 OneToMany 和 ManyToOne 连接,则会部署工件。

有谁知道为什么 Hibernate 会这样做?

【问题讨论】:

  • 你能在问题中添加Carrot.javaFatRabbit.java吗?
  • 对不起,我回家了,无法查看您的回复。但是您的评论让我浏览了 FatRabbit,我确实发现 FatRabbit 通过 JoinTable 对 Carrot 有一个吸气剂。删除它允许我成功部署代码。现在我们正在投资到底发生了什么,但至少我们知道问题出在哪里。谢谢。

标签: java hibernate jpa wildfly


【解决方案1】:

你错误地使用了@JoinColumn注解。

@Entity
public class FatRabbitCarrot {

    @Id
    @GeneratedValue
    private Long id;

    @OnToMany
    private List<NutToffee> toffies;

}

@Entity
public class NutToffee {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "fatRabbitCarrot_id")
    private FatRabbitCarrot fatRabbitCarrot;

}

这意味着您将使用连接表在FatRabbitCarrotNutToffee 之间建立关联。您将在NutToffee 表中增加一个fatRabbitCarrot_id 列。

你需要使用mappedBy

    @Entity
    public class FatRabbitCarrot {

        @Id
        @GeneratedValue
        private Long id;

        @OnToMany(mappedBy = "fatRabbitCarrot")
        private List<NutToffee> toffies;

    }

    @Entity
    public class NutToffee {

        @Id
        @GeneratedValue
        private Long id;

        @ManyToOne
        @JoinColumn(name = "fatRabbitCarrot_id")
        private FatRabbitCarrot fatRabbitCarrot;

    }

如果您不需要@ManyToOne 关联,您可以使用@JoinColumn@OneToMany 而不使用mappedBy

    @Entity
    public class FatRabbitCarrot {

        @Id
        @GeneratedValue
        private Long id;

        @OnToMany
        @JoinColumn(name = "fatRabbitCarrot_id")
        private List<NutToffee> toffies;

    }

    @Entity
    public class NutToffee {

        @Id
        @GeneratedValue
        private Long id;


    }

https://*.com/a/37542849/3405171

【讨论】:

  • 我也尝试过,但没有帮助。似乎问题在于 FatRabbit 在 FatRabbitCarrot 上有一个 JoinTable 注释,它加载了所有它的 Carrot 实例。我们仍在探索那里究竟发生了什么,但删除该 Carrot getter 允许代码部署。
  • @kozeljko 您是否尝试记录 Hibernate 用于生成数据库模式的 SQL?对吗?
  • 我们有点着急,JoinTable getter 并没有在任何地方使用(不知道为什么我们有它),所以我们只是删除了它,直到我们有更多时间来解决这个问题.
最近更新 更多