jpa - 如何创建与 IdClass 的多对多关系?

jpa - How to create a many to many relationship with an IdClass?

我有 3 个 table 具有多对多关系

我可以为休眠建模 类 以便我使用 IdClass 而不是 EmbeddedId 解决方案(这样我就可以避免使用级联不必要的级别进行调用 - getId().getA())

PS 尝试混合使用这些解决方案,但没有成功:
http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/
How to map a composite key with Hibernate?

When it comes to building relationships between entities,
the closest wall next to me and my head often join... (Stephan)

下面是实体 A 和 B 之间多对多关系的工作示例:

A.java

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

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;

@Entity
public class A {
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE)
    @Column(name="id_a")
    private Integer id;

    private String name;

    @OneToMany(mappedBy="a",cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    private List<AB> abAssociations = new ArrayList<>();

    // Getters and setters...
}

B.java

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

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;

@Entity
public class B {
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE)
    @Column(name = "id_b")
    private Integer id;

    private String name;

    @OneToMany(mappedBy = "b", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    private List<AB> abAssociations = new ArrayList<>();

    // Getters and setters...
}

AB.java

import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@IdClass(ABid.class)
public class AB {
    @Id
    @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    private A a;

    @Id
    @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    private B b;

    @Temporal(TemporalType.TIMESTAMP)
    private Date date;

    // Getters and setters...
}

ABid.java

import java.io.Serializable;

// The IdClass MUST implement Serializable and override #hashCode and #equals
public class ABid implements Serializable {

    private static final long serialVersionUID = -2834827403836993112L;

    private A a;
    private B b;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((a == null) ? 0 : a.hashCode());
        result = prime * result + ((b == null) ? 0 : b.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ABid other = (ABid) obj;
        if (a == null) {
            if (other.a != null)
                return false;
        } else if (!a.equals(other.a))
            return false;
        if (b == null) {
            if (other.b != null)
                return false;
        } else if (!b.equals(other.b))
            return false;
        return true;
    }
}

pom.xml

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.7.Final</version>
    </dependency>

示例代码

import java.util.Date;

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

public class Main {
    public static void main(String[] args) {
        // * Init entity manager
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("playground");

        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        // * Create two entities and persist them
        // We must persist the entities first alone before we build and flush their relation
        A a = new A();
        a.setName("foo");
        em.persist(a);

        B b = new B();
        b.setName("bar");
        em.persist(b);

        // * Build relationships between the two previous entities
        AB ab = new AB();
        ab.setA(a);
        ab.setB(b);
        ab.setDate(new Date());
        a.getAbAssociations().add(ab);
        b.getAbAssociations().add(ab);

        // * Flush our changements in the database
        em.getTransaction().commit();
        em.close();
        emf.close();
    }
}

这是 Hibernate 在 Postgresql 数据库上创建的表的 sql 代码。

CREATE TABLE a
(
  id_a integer NOT NULL,
  name character varying(255),
  CONSTRAINT a_pkey PRIMARY KEY (id_a)
)

CREATE TABLE b
(
  id_b integer NOT NULL,
  name character varying(255),
  CONSTRAINT b_pkey PRIMARY KEY (id_b)
)

CREATE TABLE ab
(
  date timestamp without time zone,
  b_id_b integer NOT NULL,
  a_id_a integer NOT NULL,
  CONSTRAINT ab_pkey PRIMARY KEY (a_id_a, b_id_b),
  CONSTRAINT fk_3exna7nsxvj1kv9i9pntmwlf1 FOREIGN KEY (a_id_a)
      REFERENCES a (id_a) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fk_n3jrq53nr1elew4rytocopkbu FOREIGN KEY (b_id_b)
      REFERENCES b (id_b) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

回应@valik的评论。

试试这个:

@Entity
public class AB {
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE)
    @Column(name = "id_ab")
    private Integer id;

    @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    private A a;

    @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    private B b;

    @Temporal(TemporalType.TIMESTAMP)
    private Date date;

    // Getters and setters...
}