Hibernate和H2“参照完整性约束违规” OneToMany双向映射 [英] Hibernate and H2 "Referential integrity constraint violation" for OneToMany bidirectional mapping

查看:223
本文介绍了Hibernate和H2“参照完整性约束违规” OneToMany双向映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有两个简单的豆子 - 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
公共类FatKid {

private int id;
私人字符串名称;
私人列表<汉堡>汉堡包;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name =FATKID_ID)
public int getId(){
返回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(){
返回汉堡包;
}
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
公共类Hamburger {

private int id;
私有字符串描述;
私人FatKid whoDoneAteMe;

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

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

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

}



hibernate.cfg.xml p>

 <?xml version ='1.0'encoding ='utf-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC
- // Hibernate / Hibernate配置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连接池(使用内置) - >
< property name =connection.pool_size> 1< / property>

<! - 启用Hibernate的自动会话上下文管理 - >
< property name =current_session_context_class>线程< / property>

<! - 禁用二级缓存 - >
< property name =cache.provider_class> org.hibernate.cache.NoCacheProvider< / property>

<! - 将所有执行的SQL回复到stdout - >
< property name =show_sql> true< / property>

<! - 在启动时删除并重新创建数据库模式 - >
< property name =hbm2ddl.auto> create-drop< / property>

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

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

依赖关系

 <依赖性> 
< groupId> org.hibernate< / groupId>
< artifactId> hibernate-core< / artifactId>
< version> 3.6.7.Final< / version>
< /依赖关系>

< dependency>
< groupId> com.h2database< / groupId>
< artifactId> h2< / artifactId>
< version> 1.3.160< / version>
< /依赖关系>

< dependency>
< groupId> javassist< / groupId>
< artifactId> javassist< / artifactId>
< version> 3.9.0.GA< / version>
< /依赖关系>

客户

  import org.hibernate.Session; 
import org.hibernate.SessionFactory;
导入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 =新汉堡包();
hamburger_1.setDescription(多汁的芝士四分之一磅);
hamburger_1.setWhoDoneAteMe(fk);
session.save(hamburger_1);
session.getTransaction()。commit();

session.beginTransaction();
Hamburger hamburger_2 =新汉堡包();
hamburger_2.setDescription(地面水牛汉堡配上培根和一个阳光明媚的鸡蛋);
hamburger_2.setWhoDoneAteMe(fk);
session.save(hamburger_2);
session.getTransaction()。commit();

sessionFactory.close();


$ b private static SessionFactory buildSessionFactory(){
try {
//从hibernate.cfg.xml创建SessionFactory
return新的配置()。configure()。buildSessionFactory();
}
catch(Throwable ex){
//确保您记录异常,因为它可能被吞下
抛出新的ExceptionInInitializerError(ex);



$ b $ / code>

我运行代码我输出(和截断的堆栈跟踪)
$ b $ pre $ Hibernate:insert into FatKid(FATKID_ID,name) Hibernate:插入Hamburger(HAMBURGER_ID,description,FATKID_ID)values(null,?,?)
Hibernate:插入Hamburger(HAMBURGER_ID,description, ?,?)
线程main中的异常org.hibernate.exception.ConstraintViolationException:无法插入:[Hamburger]
...
由org.h2.jdbc.JdbcSQLException引发:参照完整性约束违规:FK43797FE95067143:PUBLIC.HAMBURGER FOREIGN KEY(HAMBURGER_ID)REFERENCES PUBLIC.FATKID(FATKID_ID); SQL语句:
插入汉堡包(HAMBURGER_ID,description,FATKID_ID)values(null,?,?)[23506-160]
...
pre>

所以第一个汉堡被保存了,但是第二个汉堡被炸了。两者都应该能够使用FatKid的id作为他们的外键,但它似乎不起作用。任何洞察力将不胜感激。



谢谢,
Kevin

解决方案

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



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

  @OneToMany(cascade = CascadeType.ALL,mappedBy =whoDoneAteMe)
public List< Hamburger> getHamburgers(){
返回汉堡包;
}

然后在另一面:

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

您也许可以进一步优化您的代码。由于你的FatKid对象知道汉堡对象,并且你配置了级联,所以你可以这样做:

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

Hamburger hamburger_1 =新汉堡包();
hamburger_1.setDescription(多汁的芝士四分之一磅);
hamburger_1.setWhoDoneAteMe(fk);
fk.getHamburgers()。add(hamburger1);

Hamburger hamburger_2 =新汉堡包();
hamburger_2.setDescription(地面水牛汉堡配上培根和一个阳光明媚的鸡蛋);
hamburger_2.setWhoDoneAteMe(fk);
fk.getHamburgers()。add(hamburger2);

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

sessionFactory.close();

上面的代码应该只用一次提交操作就可以保存完整的对象图,并保存在单个事务中。 / p>

So I have two simple beans -- FatKid and Hamburgers. Now, for reasons unbeknownst to me I need to be able to not only look up all of the hamburgers someone ate, but also who ate which particular hamburger. Onto the code!

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);
        }
    }

}

So when I run the code I end up with 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]
        ...

So the first Hamburger is saved but it then blows up on the second. Both should be able to use the FatKid's id as their foreign key but it doesn't seem to work. Any insight would be greatly appreciated.

Thanks, Kevin

解决方案

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.

这篇关于Hibernate和H2“参照完整性约束违规” OneToMany双向映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆