【问题标题】:Hibernate - ManyToOne & Inheritance / JOINED / mappedByHibernate - ManyToOne & Inheritance / JOINED / mappedBy
【发布时间】:2014-03-07 13:57:39
【问题描述】:

我在继承映射方面遇到了一些问题。这是我的数据库结构:

及相关实体:

抽象实体:

@MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> implements Serializable {

@Id @GeneratedValue(strategy = IDENTITY)
@Column(unique = true, updatable = false, nullable = false)
private ID id;

public ID getId() {
return id;
}
@SuppressWarnings("unused")
public void setId(ID id) {
this.id = id;
}

UserAcitvity 实体:

@Entity @Table(name = "user_activity")
@Inheritance(strategy = JOINED)
@AttributeOverride(name = "id", column = @Column(name = "ua_id"))
public abstract class UserActivity extends AbstractEntity<Long> {

@ManyToOne(cascade = { MERGE, PERSIST }, fetch = LAZY)
@JoinColumn(name = "ua_user_id")
private User user;

...
}

评论实体:

@Entity @Table(name = "comment")
@PrimaryKeyJoinColumn(name = "cm_id")
public class Comment extends UserActivity {

@ManyToOne(cascade = { MERGE, PERSIST }, fetch = LAZY)
@JoinColumn(name = "cm_question_id")
private Question question;

...
}

问题实体:

@Entity @Table(name = "question")
@PrimaryKeyJoinColumn(name = "qs_id")
public class Question extends UserActivity {

...

@OneToMany(fetch = LAZY, cascade = ALL, mappedBy = "question")
private List<Answer> answers = new ArrayList<>();

@OneToMany(fetch = LAZY, cascade = ALL, mappedBy = "question")
private List<Comment> comments = new ArrayList<>();

...
}

回答实体:

@Entity @Table(name = "answer")
@PrimaryKeyJoinColumn(name = "asw_id")
public class Answer extends UserActivity {

@ManyToOne(cascade = { MERGE, PERSIST }, fetch = LAZY)
@JoinColumn(name = "asw_question_id")
private Question question;

...
}

和用户实体:

@Entity @Table(name = "user")
@AttributeOverride(name = "id", column = @Column(name = "user_id"))
public class User extends AbstractEntity<Long> {

...
@OneToMany(cascade = REMOVE)
private List<Question> questions = new ArrayList<>();

@OneToMany(cascade = REMOVE)
private List<Answer> answers = new ArrayList<>();

@OneToMany(cascade = REMOVE)
private List<Comment> comments = new ArrayList<>();
...
}

问题:

当我尝试保存或删除 User 时,出现异常:

org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [insert into user_question (user_user_id, questions_qs_id) values (?, ?)]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement

和:

org.hibernate.engine.jdbc.spi.SqlExceptionHelper : 147 = user lacks privilege or object not found: USER_ANSWER

Hibernate 正在尝试创建一个表:user_questionuser_answer不需要

我应该做些什么来修复?

【问题讨论】:

  • USER_ANSWER 和 USER_QUESTION 不会出现在您的数据库架构或映射中。一定少了一些东西!
  • @Julien 是的,我知道。这是因为我没有添加mappedBy。我无法通过UserActivity 将其添加到user 字段。
  • 您能否在将ua_user_id 保留在user_activity 表中的同时解决此问题?
  • @Snekse 嘿。我真的不记得我是怎么做到的。检查full source code in GitHub希望它会帮助你。 iss59-jooq 分支上调查它,因为在 master 它从 Hibernate 移到 JOOQ 上

标签: java mysql spring hibernate maven


【解决方案1】:

我认为您不能通过将ManyToOne 关联映射到User 通常在UserActivity 实体中实现此目的。对于 JPA 提供程序(Hibernate)来说,这可能太令人困惑了。

相反,我认为您需要将关联映射到QuestionAnswerComment 实体中的每个 中的User。是的,我知道这将是重复的代码,但它看起来是您能够使用 mappedBy 引用限定 User 中的 OneToMany 映射的唯一方法。

例如,您的 Question 实体的关联定义为:

@ManyToOne(cascade = { MERGE, PERSIST }, fetch = LAZY)
@JoinColumn(name = "ua_user_id")
private User questionUser;

根据 Hibernate 对上述关联的聪明程度(或不聪明),您可能需要在 JoinColumn 注释中指定 table="USER_ACTIVITY"

那么User 的 OneToMany 将是:

@OneToMany(mappedBy="questionUser", cascade = REMOVE)
private List<Question> questions = new ArrayList<>();

AnswerComment 中的每一个都类似。

当然,我没有尝试过,所以我可能是错的。

【讨论】:

    【解决方案2】:

    这可能是因为当您设置 @OneToMany 映射时,休眠将创建一个辅助表,该表将存储关系上实体的 id。

    在这种情况下,您应该尝试以下方法:

    @OneToMany(cascade = REMOVE)
    @JoinColumn(name = "answer_id")
    private List<Answer> answers = new ArrayList<>();
    

    @JoinColumn 注释将映射关系而无需创建辅助表,因此该解决方案很可能会在这种情况下为您提供帮助。

    【讨论】:

    • 在可能的情况下,删除mappedBy 是关键。请参阅问题线程上的 OP 评论。
    【解决方案3】:

    试试这个映射,根据section 2.2.5.3.1.1 of the documentation,这应该可以正常工作:

    @Entity
    public class User {
        @OneToMany(cascade = REMOVE) 
        @JoinColumn(name="user_fk") //we need to duplicate the physical information
        private List<Question> questions = new ArrayList<>();
            ...
    }
    
    @Entity
    public class Question {
        @ManyToOne
        @JoinColumn(name="user_fk", insertable=false, updatable=false)
        private User user;
        ...
    }
    

    创建辅助关联的原因是,Hibernate 无法知道关系的多方(例如 Question)有一个外键返回给 User,它对应于与 @ 完全相同的关系987654323@.

    Question.user 关联可以是完全不同的关联,例如User.questionCreatorUser.previousSuccessfulAnswerer

    仅通过查看Question.user,Hibernate 无法知道它与User.questions 是同一个关联。

    所以没有mappedBy表示关系相同,或者@JoinColumn表示没有连接表(但只有一个连接列),Hibernate会触发通用的一对多关联映射方案这包括创建一个辅助映射表。

    schema 遗漏了这样的关联表,导致的错误可以通过上面的映射解决。

    【讨论】:

      【解决方案4】:

      如果您希望在实体关系中使用单向的一对多。
      试试..JoinTable

      @OneToMany(cascade = REMOVE)
      @JoinTable(name = "user_question", joinColumns = {
          @JoinColumn(name = "user_id")}, inverseJoinColumns = {
          @JoinColumn(name = "qs_id")})
      private List<Question> questions = new ArrayList<>();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-25
        • 2014-02-25
        • 2014-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-24
        相关资源
        最近更新 更多