Hibernate 和 H2“引用完整性约束违规”用于 OneToMany 双向映射

发布于 2024-12-11 09:00:33 字数 6755 浏览 1 评论 0原文

我有两种简单的豆子——FatKid 和汉堡包。我不仅需要能够查找某人吃过的所有汉堡包,还需要能够查找谁吃了哪个特定的汉堡包。

FatKid.java

import java.util.List;
import javax.persistence.CascadeType;
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.OneToMany;
import javax.persistence.Table;

@Table
@Entity
public class FatKid {
    
    private int id;
    private String name;
    private List<Hamburger> hamburgers;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "FATKID_ID")
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

    @Column
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name="HAMBURGER_ID")
    public List<Hamburger> getHamburgers() {
        return hamburgers;
    }
    public void setHamburgers(List<Hamburger> hamburgers) {
        this.hamburgers = hamburgers;
    }

}

Hamburger.java

import javax.persistence.CascadeType;
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;

@Table
@Entity
public class Hamburger {

    private int id;
    private String description;
    private FatKid whoDoneAteMe;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "HAMBURGER_ID")
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

    @Column
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="FATKID_ID")
    public FatKid getWhoDoneAteMe() {
        return whoDoneAteMe;
    }
    public void setWhoDoneAteMe(FatKid whoDoneAteMe) {
        this.whoDoneAteMe = whoDoneAteMe;
    }

}

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.url">jdbc:h2:~/routesetting</property>
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">create-drop</property>

        <mapping class="FatKid" />
        <mapping class="Hamburger" />

    </session-factory>
</hibernate-configuration>

依赖

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>3.6.7.Final</version>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.3.160</version>
</dependency>

<dependency>
    <groupId>javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.9.0.GA</version>
</dependency>

项 client

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class OmNom {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    public static void main(String[] args) {

        Session session = sessionFactory.openSession();

        session.beginTransaction();
        FatKid fk = new FatKid();
        fk.setName("Darrell");
        session.save(fk);
        session.getTransaction().commit();

        session.beginTransaction();
        Hamburger hamburger_1 = new Hamburger();
        hamburger_1.setDescription("Juicy quarter pounder with cheese");
        hamburger_1.setWhoDoneAteMe(fk);
        session.save(hamburger_1);
        session.getTransaction().commit();

        session.beginTransaction();
        Hamburger hamburger_2 = new Hamburger();
        hamburger_2.setDescription("Ground buffalo burger topped with bacon and a sunny-side egg");
        hamburger_2.setWhoDoneAteMe(fk);
        session.save(hamburger_2);
        session.getTransaction().commit();

        sessionFactory.close();

    }

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            throw new ExceptionInInitializerError(ex);
        }
    }

}

输出(和截断的堆栈跟踪):

Hibernate: insert into FatKid (FATKID_ID, name) values (null, ?)
Hibernate: insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?)
Hibernate: insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?)
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not insert: [Hamburger]
        ...
Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK43797FE95067143: PUBLIC.HAMBURGER FOREIGN KEY(HAMBURGER_ID) REFERENCES PUBLIC.FATKID(FATKID_ID)"; SQL statement:
insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?) [23506-160]
        ...

第一个汉堡包被保存,但在第二个汉堡包上爆炸。

我怎样才能让它使用 FatKid 的 id 作为外键?

I have two simple beans--FatKid and Hamburgers. I need to be able to not only look up all of the hamburgers someone ate, but also who ate which particular hamburger.

FatKid.java

import java.util.List;
import javax.persistence.CascadeType;
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.OneToMany;
import javax.persistence.Table;

@Table
@Entity
public class FatKid {
    
    private int id;
    private String name;
    private List<Hamburger> hamburgers;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "FATKID_ID")
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

    @Column
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name="HAMBURGER_ID")
    public List<Hamburger> getHamburgers() {
        return hamburgers;
    }
    public void setHamburgers(List<Hamburger> hamburgers) {
        this.hamburgers = hamburgers;
    }

}

Hamburger.java

import javax.persistence.CascadeType;
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;

@Table
@Entity
public class Hamburger {

    private int id;
    private String description;
    private FatKid whoDoneAteMe;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "HAMBURGER_ID")
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

    @Column
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="FATKID_ID")
    public FatKid getWhoDoneAteMe() {
        return whoDoneAteMe;
    }
    public void setWhoDoneAteMe(FatKid whoDoneAteMe) {
        this.whoDoneAteMe = whoDoneAteMe;
    }

}

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.url">jdbc:h2:~/routesetting</property>
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">create-drop</property>

        <mapping class="FatKid" />
        <mapping class="Hamburger" />

    </session-factory>
</hibernate-configuration>

dependencies

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>3.6.7.Final</version>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.3.160</version>
</dependency>

<dependency>
    <groupId>javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.9.0.GA</version>
</dependency>

client

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class OmNom {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    public static void main(String[] args) {

        Session session = sessionFactory.openSession();

        session.beginTransaction();
        FatKid fk = new FatKid();
        fk.setName("Darrell");
        session.save(fk);
        session.getTransaction().commit();

        session.beginTransaction();
        Hamburger hamburger_1 = new Hamburger();
        hamburger_1.setDescription("Juicy quarter pounder with cheese");
        hamburger_1.setWhoDoneAteMe(fk);
        session.save(hamburger_1);
        session.getTransaction().commit();

        session.beginTransaction();
        Hamburger hamburger_2 = new Hamburger();
        hamburger_2.setDescription("Ground buffalo burger topped with bacon and a sunny-side egg");
        hamburger_2.setWhoDoneAteMe(fk);
        session.save(hamburger_2);
        session.getTransaction().commit();

        sessionFactory.close();

    }

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            throw new ExceptionInInitializerError(ex);
        }
    }

}

The output (and truncated stack trace):

Hibernate: insert into FatKid (FATKID_ID, name) values (null, ?)
Hibernate: insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?)
Hibernate: insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?)
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not insert: [Hamburger]
        ...
Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK43797FE95067143: PUBLIC.HAMBURGER FOREIGN KEY(HAMBURGER_ID) REFERENCES PUBLIC.FATKID(FATKID_ID)"; SQL statement:
insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?) [23506-160]
        ...

The first Hamburger is saved but it blows up on the second.

How can I get it to use the FatKid's id as their foreign key?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

渔村楼浪 2024-12-18 09:00:33

你的映射对我来说看起来很奇怪。关系的两侧都有一个@JoinColumn,每个都指向另一个表的主键。这似乎不是 OneToMany 关系。

您的 OneToMany 应该告诉关系的所有者:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "whoDoneAteMe")
public List<Hamburger> getHamburgers() {
    return hamburgers;
}

然后在另一边:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "fatkid_id")
public FatKid getWhoDoneAteMe() {
    return whoDoneAteMe;
}

您也可以进一步优化您的代码。由于您的 FatKid 对象知道汉堡对象并且您已经配置了级联,因此您可以执行以下操作:

    session.beginTransaction();
    FatKid fk = new FatKid();
    fk.setName("Darrell");

    Hamburger hamburger_1 = new Hamburger();
    hamburger_1.setDescription("Juicy quarter pounder with cheese");
    hamburger_1.setWhoDoneAteMe(fk);
    fk.getHamburgers().add(hamburger1);

    Hamburger hamburger_2 = new Hamburger();
    hamburger_2.setDescription("Ground buffalo burger topped with bacon and a sunny-side egg");
    hamburger_2.setWhoDoneAteMe(fk);
    fk.getHamburgers().add(hamburger2);

    session.save(fk);
    session.getTransaction().commit();

    sessionFactory.close();

上面的代码应该仅通过一次提交操作并在单个事务中保存完整的对象图。

Your mappings look weird to me. You have a @JoinColumn in both sides of the relationship, each pointing to the primary key of the other table. That doesn't seem to be a OneToMany relationship.

Your OneToMany should tell the owner of the relationship:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "whoDoneAteMe")
public List<Hamburger> getHamburgers() {
    return hamburgers;
}

and then in the other side:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "fatkid_id")
public FatKid getWhoDoneAteMe() {
    return whoDoneAteMe;
}

You might be able to optimize your code further too. As your FatKid objects are aware of the Hamburger objects and you have configured cascading, you could do:

    session.beginTransaction();
    FatKid fk = new FatKid();
    fk.setName("Darrell");

    Hamburger hamburger_1 = new Hamburger();
    hamburger_1.setDescription("Juicy quarter pounder with cheese");
    hamburger_1.setWhoDoneAteMe(fk);
    fk.getHamburgers().add(hamburger1);

    Hamburger hamburger_2 = new Hamburger();
    hamburger_2.setDescription("Ground buffalo burger topped with bacon and a sunny-side egg");
    hamburger_2.setWhoDoneAteMe(fk);
    fk.getHamburgers().add(hamburger2);

    session.save(fk);
    session.getTransaction().commit();

    sessionFactory.close();

The above code should save the complete object graph with just one commit operation and in a single transaction.

横笛休吹塞上声 2024-12-18 09:00:33

我在尝试“INSERT INTO”操作时遇到“引用完整性约束违规”错误。出现此问题是因为我试图插入一个实体,该实体的外键指向尚未创建的表条目。

为了解决这个问题,我采取了以下步骤:我首先在引用的表中插入一条新记录,获取一个新的主键值。然后,使用这个新密钥,我能够成功插入所需的实体,而不会出现任何其他问题。

I encountered the "Referential Integrity Constraint Violation" error when attempting an "INSERT INTO" operation. This issue arose because I was trying to insert an entity that had a foreign key pointing to a table entry that hadn't been created yet.

To resolve this problem, I took the following steps: I first inserted a new record into the referenced table, obtaining a new primary key value. Then, using this new key, I was able to successfully insert the desired entity without any further issues.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文