簡體   English   中英

如何在JPA中實現復雜的多對多關系?

[英]How to implement a complex many to many relationship in JPA?

這里的數據庫架構

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

由於某些原因,我不斷收到錯誤消息

Concrete type "class models.OrderDetail" with application identity does not declare any primary key fields.

誰能指出我的問題所在? 謝謝

當我之前這樣做時(如本問答中所述 ),我在可嵌入ID原語中創建了字段(對應於所引用實體的ID字段),然后在實體中使用@MapsId 我相信這是滿足所有要求的最簡單的方法(我敢說是對的):實體中的字段是關系,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() {}
}

首先, OrderDetailPK必須實現Serializable

其次,請指定您要使用的ID,因為您已將product_idorder_id列指定為insertable=false, updatable=false (只讀)。

因此,您需要嘗試以下操作:

@EmbeddedId
@AttributeOverrides({
        @AttributeOverride(name = "product_id",column = @Column(name = "product_id")),
        @AttributeOverride(name = "listingId",column= @Column(name = "order_id"))
})
private OrderDetailPK id;

您可以在這里找到更多信息:

http://docs.oracle.com/javaee/6/api/javax/persistence/EmbeddedId.html

http://docs.oracle.com/javaee/6/api/javax/persistence/AttributeOverride.html

EmbeddedId javadoc:

不支持在嵌入式id類中定義的關系映射。

所以你不能用這種方式。 我不認為JPA 1指定了實現此目標的標准方法(在JPA 2中有@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保留在實體中的字段上,但我沒有重新檢查它們是否是必需的)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM