【问题标题】:hibernate and mappedBy: Is it possible to automatically set foreign key without setting bidirectional relationship among objects?hibernate和mappedBy:是否可以自动设置外键而不设置对象之间的双向关系?
【发布时间】:2018-07-26 19:15:36
【问题描述】:

欢迎,

我有 2 个课程:对话和问题。一次对话有很多问题。

Conversation.java:

package com.jcg.jpa.mappedBy;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "CONVERSATION_TABLE")
public class Conversation implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "CONV_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int conversationId;

@Column(name = "CONV_NAME")
private String name;

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="conversation")
private Collection<Question> questions = new ArrayList<Question>();

public Conversation() { }

public int getConversationId() {
    return conversationId;
}

public void setConversationId(int conversationId) {
    this.conversationId = conversationId;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Collection<Question> getQuestions() {
    return questions;
}

public void setQuestions(Collection<Question> questions) {
    this.questions = questions;
}

@Override
public String toString() {
    return "Employee [conversationId=" + conversationId + ", name=" + name + "]";
}
}

问题.java:

package com.jcg.jpa.mappedBy;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "QUESTION_TABLE")
public class Question implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;

@ManyToOne
@JoinColumn(name = "CONVERSATION_CONV_ID", nullable = false)
private Conversation conversation;


@Column(name = "QUESTION_TEXT")
private String questionText;

@Column(name = "ANSWER_TEXT")
private String answerText;



public Question() { }

public int getId() {
    return id;
}

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

public String getQuestionText() {
    return questionText;
}

public void setQuestionText(String questionText) {
    this.questionText = questionText;
}

public String getAnswerText() {
    return answerText;
}

public void setAnswerText(String answerText) {
    this.answerText = answerText;
}

public Conversation getConversation() {
    return conversation;
}

public void setConversation(Conversation conversation) {
    this.conversation = conversation;
}

@Override
public String toString() {
    return "Question [id=" + id +  ", questionText=" + questionText
            + ", answerText=" + answerText +"]";
}
}

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="JPAMappedbyExample" transaction-type="RESOURCE_LOCAL">
    <class>com.jcg.jpa.mappedBy.Conversation</class>
    <class>com.jcg.jpa.mappedBy.Question</class>

    <!-- Configuring The Database Connection Details -->
    <properties>
        <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpatest" />
        <property name="javax.persistence.jdbc.user" value="root" />
        <property name="javax.persistence.jdbc.password" value="qwerty" />

    </properties>
</persistence-unit>

现在在 Main.java 我试图用两个问题创建对话:

package com.jcg.jpa.mappedBy;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

private static final EntityManagerFactory emFactoryObj;
private static final String PERSISTENCE_UNIT_NAME = "JPAMappedbyExample";   

static {
    emFactoryObj = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
}

// This Method Is Used To Retrieve The 'EntityManager' Object
public static EntityManager getEntityManager() {
    return emFactoryObj.createEntityManager();
}

private static void insertRecords() {
    EntityManager entityMgrObj = getEntityManager();
    if (null != entityMgrObj) {
        entityMgrObj.getTransaction().begin();

        Conversation conv = new Conversation();
        conv.setName("Discussion about something");

        Question question1 = new Question();
        question1.setQuestionText("2 plus 2");
        question1.setAnswerText("four");
        question1.setConversation(conv);

        Question question2 = new Question();
        question2.setQuestionText("what is Your name");
        question2.setAnswerText("Adam");
        question2.setConversation(conv);

        List<Question> questions = new ArrayList<Question>();
        questions.add(question1);
        questions.add(question2);
        conv.setQuestions(questions);

        entityMgrObj.persist(conv);
        entityMgrObj.getTransaction().commit();

        entityMgrObj.clear();
        System.out.println("Record Successfully Inserted In The Database");
    }
}



public static void main(String[] args) {
    insertRecords();

}
}

在 insertRecords() 中,我正在创建 conv 和两个问题。 每个问题都有对话:

question1.setConversation(conv);
question2.setConversation(conv);

接下来,创建一个包含这 2 个问题的问题列表 并设置为转换问题列表:

conv.setQuestions(questions); 

它工作正常,因为数据被插入到两个表中, 并且外键 CONVERSATION_CONV_ID 已填充:

但是,当我删除问题中的设置对话时,行:

question1.setConversation(conv);
question2.setConversation(conv);

外键设置为NULL。为什么?我们已经在对话问题列表中添加了两个问题:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="conversation")
private Collection<Question> questions = new ArrayList<Question>();

,所以hibernate应该知道这两个问题的会话外键是什么(因为它们位于指定的会话问题列表中)。那么是否可以避免为每个问题设置 Conversation 并且只将问题添加到 Conversation 的问题列表中?我应该如何配置实体来做到这一点?或者这可能是不可能的,我们总是需要设置两个方向?

【问题讨论】:

    标签: java hibernate hibernate-mapping mappedby


    【解决方案1】:

    所以hibernate应该知道这两个问题的会话外键是什么(因为它们位于指定的会话问题列表中)。

    No Hibernate 不应该知道这两个Questions 中的Conversation 是什么,如果你不使用setConversation() 指定它,因为它在这里处理对象,而这两个questions 没有Conversation 所属的任何指示。

    说明:

    因为当您只将这两个questions 添加到Conversation 对象时,此信息在Questions 对象中将不可见。

    这里还有一件事,mappedBy 属性表明object 是映射的所有者,那么如果mappedBy 端没有给定对象,如何进行映射?

    这就是为什么您应该在Question 对象中指定Conversation,以便Hibernate 可以正确评估映射。

    注意:

    建议为OneToMany 映射使用Set 而不是任何其他Collection,因为此集合不应有任何重复,因此您最好将其更改为:

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="conversation")
    private Set<Question> questions = new HashSet<Question>();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-11
      • 2018-07-23
      • 1970-01-01
      • 2021-08-24
      • 2019-04-16
      • 1970-01-01
      • 2017-11-13
      • 2015-02-14
      相关资源
      最近更新 更多