Hibernate 中的双向一对一关系

Bidirectional one-to-one relationships in Hibernate

有两个table:飞机和引擎

引擎 table 的组成如下 [Engine_ID, Engine_Name,Airplane_Owner_ID]
飞机 table 组成如下 [Airplane_ID, Left_Engine, Right_Engine]

Left_Engine和Right_Engine是引擎table的外键,此外Airplane_Owner_ID是飞机table的外键。因此在飞机和引擎之间定义了三个一对一的关系 tables.

我知道如何指定两个 table 之间的单个一对一关系,但如何指定两个 table 之间的多个关系?是同一个流程吗?

如何在 Hibernate 中指定这些关系?

"Left_Engine and Right_Engine are foreign keys from the Engine table,
moreover Airplane_Owner_ID is the foreign key from the Airplane table."

您的问题是 AirplaneEngine 引用,而 EngineAirplane 引用。在您的数据模型中,每个 table 都是另一个的 child。循环依赖在数据库中和在堆栈的其他部分一样糟糕。

最好的解决办法是修复数据模型。

  • Airplane
  • 中删除 Left_EngineRight_Engine
  • Engine_Position 添加到 Engine
  • Engine (Airplane_Owner_ID, Engine_Position)
  • 上添加唯一约束
  • 还在 Engine_Position 上为 LEFT、RIGHT 添加检查约束,或在参考数据上使用外键 table

这个模型有两个优点:

  1. 清晰的所有权 - 飞机拥有引擎,引擎不拥有飞机。
  2. 轻松支持不同引擎配置的飞机(一、三、四……)

正如@APC 所说,引擎和飞机之间的循环依赖是一个糟糕的设计。但是使用下面描述的解决方案,Engine.Airplane_Owner_ID 只能作为逻辑后备 link 实现,而数据库 table 中不存在。

Airplane.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping">
<hibernate-mapping>
    <class name="Airplane" table="AIRPLANE">
        <id name="id" type="int" column="AIRPLANE_ID">
            <generator class="native"/>
        </id>
        <property name="name" column="AIRPLANE_NAME" type="string" length="250"/>
        <many-to-one name="rightEngine" class="Engine" cascade="save-update" unique="true"/>
        <many-to-one name="leftEngine" class="Engine" cascade="save-update" unique="true"/>
    </class>
</hibernate-mapping>

Engine.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping">
<hibernate-mapping>
    <class name="Engine" table="ENGINE">
        <id name="id" type="int" column="ENGINE_ID">
            <generator class="native"/>
        </id>
        <property name="name" column="ENGINE_NAME" type="string" length="250"/>
        <property name="position" column="ENGINE_POSITION" type="java.lang.Byte" />

        <one-to-one name="ownerAirplane" property-ref="rightEngine" />
    </class>
</hibernate-mapping>

Airplane.java

public class Airplane {
    private int id;
    private String name;

    private Engine rightEngine;
    private Engine leftEngine;

    public Airplane(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Engine getRightEngine() {
        return rightEngine;
    }

    public void setRightEngine(Engine rightEngine) {
        this.rightEngine = rightEngine;
    }

    public Engine getLeftEngine() {
        return leftEngine;
    }

    public void setLeftEngine(Engine leftEngine) {
        this.leftEngine = leftEngine;
    }

    @Override
    public String toString() {
        return "Airplane{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", rightEngline=" + (rightEngine == null ? null : rightEngine.getName()) +
                ", leftEngine=" + (leftEngine == null ? null : leftEngine.getName()) +
                '}';
    }
}

Engine.java

public class Engine {

    private int id;
    private String name;
    private byte position;//0=left, 1=right
    private Airplane ownerAirplane;

    /**
     * @param name
     * @param position 0=left, 1=right
     */
    public Engine(String name, byte position) {
        this.name = name;
        this.position = position;
    }

    public Airplane getOwnerAirplane() {
        return ownerAirplane;
    }

    public void setOwnerAirplane(Airplane ownerAirplane) {
        this.ownerAirplane = ownerAirplane;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }


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

    /**
     * @return 0=left, 1=right
     */
    public byte getPosition() {
        return position;
    }

    /**
     * @param position 0=left, 1=right
     */
    public void setPosition(byte position) {
        this.position = position;
    }


    @Override
    public String toString() {
        return "Engine{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", position=" + position +
                ", ownerAirplane=" + (ownerAirplane == null ? null : ownerAirplane.getName()) +
                '}';
    }
}

Main.java

 public static void main(final String[] args) throws Exception {

        Session session = ourSessionFactory.openSession();
        Transaction transaction = null;
        try {
            transaction = session.beginTransaction();
            Engine engineRight1 = new Engine("engineRight1", (byte) 1);
            Engine engineLeft1 = new Engine("engineLeft1", (byte) 0);
            Airplane airplane1 = new Airplane("Airplane1");

            Engine engineRight2 = new Engine("engineRight2", (byte) 1);
            Engine engineLeft2 = new Engine("engineLeft2", (byte) 0);
            Airplane airplane2 = new Airplane("Airplane2");

            Engine engineRight3 = new Engine("engineRight3", (byte) 1);
            Engine engineLeft3 = new Engine("engineLeft3", (byte) 0);
            Airplane airplane3 = new Airplane("Airplane3");

            engineLeft1.setOwnerAirplane(airplane1);
            engineRight1.setOwnerAirplane(airplane1);
            airplane1.setLeftEngine(engineLeft1);
            airplane1.setRightEngine(engineRight1);

            engineRight2.setOwnerAirplane(airplane2);
            airplane2.setRightEngine(engineRight2);
//            airplane2.setLeftEngine(engineLeft1);

            engineRight3.setOwnerAirplane(airplane3);
            airplane3.setLeftEngine(engineLeft3);

            session.save(airplane1);
            session.save(airplane2);
            session.save(airplane3);

            session.save(engineLeft1);
            session.save(engineLeft2);
            session.save(engineLeft3);
            session.save(engineRight1);
            session.save(engineRight2);
            session.save(engineRight3);

            transaction.commit();
        } catch (HibernateException e) {
            transaction.rollback();
            e.printStackTrace();
        }