Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在JPA中实现复杂的多对多关系?_Java_Jpa - Fatal编程技术网

Java 如何在JPA中实现复杂的多对多关系?

Java 如何在JPA中实现复杂的多对多关系?,java,jpa,Java,Jpa,这里是db模式 CREATE TABLE Products ( id INT NOT NULL AUTO_INCREMENT, category_id INT NOT NULL, description VARCHAR(100), price DECIMAL(10, 2) NOT NULL, PRIMARY KEY (id), FOREIGN KEY (category_id) REFERENCES Categori

这里是db模式

CREATE TABLE Products
(
    id          INT NOT NULL AUTO_INCREMENT,
    category_id  INT NOT NULL,
    description VARCHAR(100),
    price       DECIMAL(10, 2) NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (category_id) REFERENCES Categories(id)
) ENGINE = INNODB;

CREATE TABLE Orders
(
    id           INT NOT NULL AUTO_INCREMENT,
    customer_id  INT NOT NULL,
    status       VARCHAR(20) NOT NULL,
    date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    FOREIGN KEY (customer_id) REFERENCES Customers(id)
) ENGINE = INNODB;

CREATE TABLE OrderDetails
(
    product_id INT NOT NULL,
    order_id   INT NOT NULL,
    quantity   INT NOT NULL,
    subtotal   DECIMAL(10, 2) NOT NULL,
    PRIMARY KEY (product_id, order_id),
    FOREIGN KEY (product_id) REFERENCES Products(id),
    FOREIGN KEY (order_id)   REFERENCES Orders(id)
) ENGINE = INNODB;
模型

@Embeddable
public class OrderDetailPK
{
    private Product product;
    private Order order;

    public OrderDetailPK() {}

    public OrderDetailPK(Product product, Order order)
    {
        this.product = product;
        this.order   = order;
    }
}

public class OrderDetail {
    @EmbeddedId
    private OrderDetailPK id;

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="product_id", insertable=false, updatable=false)
    private Product product;

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="order_id", insertable=false, updatable=false)
    private Order order;

    private int quantity;
    private double subtotal;

    public OrderDetail() {}

    public OrderDetail(OrderDetailPK id, int quantity, double subtotal)
    {
        this.product  = id.getProduct();
        this.order    = id.getOrder();
        this.quantity = quantity;
        this.subtotal = subtotal;
    }
    // getters, setters
}

public class Product {
    @Id
    private int id;

    private String description;
    private double price;

    @ManyToOne
    @JoinColumn(name="category_id")
    private Category category;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "Products")
    private List<OrderDetail> orderDetail;
}

public class Order {
    @Id
    private int id;

    @ManyToOne
    @JoinColumn(name="customer_id")
    private Customer customer;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "Orders")
    private List<OrderDetail> orderDetail;
}

有人能告诉我问题出在哪里吗?谢谢

首先,
OrderDetailPK
必须实现
Serializable

第二,请指定要使用的ID,因为您已将列
product\u ID
order\u ID
指定为
insertable=false,updateable=false
(只读)

因此,您需要尝试以下方法:

@EmbeddedId
@AttributeOverrides({
        @AttributeOverride(name = "product_id",column = @Column(name = "product_id")),
        @AttributeOverride(name = "listingId",column= @Column(name = "order_id"))
})
private OrderDetailPK id;
您可以在此处找到更多信息:


EmbeddedId
javadoc:

不支持在嵌入式id类中定义的关系映射

所以你不能这样做。我不认为JPA1指定了一种标准的实现方法(在JPA2中有
@MapsId
,但我从未尝试过),但这是我通常做的,大多数实现(我认为至少Hibernate、EclipseLink和OpenJPA)都支持它:

使用基元类型声明主键类:

@Embeddable
public class OrderDetailPK implements Serializable
{
    private int product;
    private int order;

    public OrderDetailPK() {}

    ...
}
使用
@IdClass
注释实体,并使用相同的名称声明字段,但声明所需的类型:

@Entity
@IdClass(OrderDetailPK.class)
public class OrderDetail {
    @Id
    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="product_id", insertable=false, updatable=false)
    private Product product;

    @Id
    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="order_id", insertable=false, updatable=false)
    private Order order;

    ...
}
(我一直在实体中的字段上保留
@Id
,但我没有重新检查它们是否是强制性的)

当我之前这样做时(如中所述),我在可嵌入Id原语中创建字段(对应于所指实体的Id字段),然后在实体中使用。我相信这是满足所有要求的最简单(我敢说是正确的):实体中的字段是关系,ID类中的字段是基本字段,每个列只映射一次(
@MapsId
字段不是真正的映射,而是某种别名)

将其应用到您的案例中,ID类如下所示:

@Embeddable
public class OrderDetailPK {
    private final int productId;
    private final int orderId;

    public OrderDetailPK(int productId, int orderId) {
        this.productId = productId;
        this.orderId = orderId;
    }
}
public class OrderDetail {
    @EmbeddedId
    private OrderDetailPK id;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("productId")
    private Product product;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("orderId")
    private Order order;

    private int quantity;
    private double subtotal;

    public OrderDetail(Product product, Order order, int quantity, double subtotal) {
        this.id = new OrderDetailPK(product.getId(), order.getId());
        this.product = product;
        this.order = order;
        this.quantity = quantity;
        this.subtotal = subtotal;
    }

    protected OrderDetail() {}
}
实体类如下所示:

@Embeddable
public class OrderDetailPK {
    private final int productId;
    private final int orderId;

    public OrderDetailPK(int productId, int orderId) {
        this.productId = productId;
        this.orderId = orderId;
    }
}
public class OrderDetail {
    @EmbeddedId
    private OrderDetailPK id;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("productId")
    private Product product;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("orderId")
    private Order order;

    private int quantity;
    private double subtotal;

    public OrderDetail(Product product, Order order, int quantity, double subtotal) {
        this.id = new OrderDetailPK(product.getId(), order.getId());
        this.product = product;
        this.order = order;
        this.quantity = quantity;
        this.subtotal = subtotal;
    }

    protected OrderDetail() {}
}

为什么不像其他实体一样,为OrderDetail使用一个技术性的非复合主键呢。事情会简单得多(而且效率高)。@JBNizet:在某些方面更简单,在其他方面则不然。为什么你认为它会更有效?因为一个数据库索引一个数值比一个索引两个数值更有效。但主要的一点是简单。在应用程序的每个级别使用单个值来标识订单详细信息,将比使用两个值简单得多。仅供参考,我遇到了一个新错误
OrderDetail.id“不能作为主键。它的类型不受支持
,您需要像我一样删除
OrderDetail.id