【问题标题】:SchemaGen wrongly generates unnecessary association tablesSchemaGen 错误地生成了不必要的关联表
【发布时间】:2021-02-21 12:28:13
【问题描述】:

我有一个非常简单的数据库模式,经典的Order ---(一对多)---> OrderItem

但是,当我使用 SchemaGen 生成 DDL 时,它会创建一个额外的层 orders_orders_item 和 product_orders_item,实际上是添加了一个冗余的关联表层:

create table orders (order_id bigint not null auto_increment, order_amout varchar(255), primary key (order_id)) engine=InnoDB;
create table orders_item (orders_item_id bigint not null auto_increment, order_amount integer, product_id bigint not null, primary key (orders_item_id)) engine=InnoDB;
create table orders_orders_item (OrderEntity_order_id bigint not null, orderItems_orders_item_id bigint not null) engine=InnoDB;
create table product (id bigint not null auto_increment, name varchar(255), price decimal(19,2), primary key (id)) engine=InnoDB;
create table product_orders_item (ProductEntity_id bigint not null, orders_orders_item_id bigint not null) engine=InnoDB;

似乎认为 orders 和 orders_item 之间以及 product 之间存在 多对多 关联和 orders_item。

为什么会这样?

我的实体类如下所示:

订单:

@Entity
@Table(name = "orders")
public class OrderEntity {

    @Id
    @Column(name = "order_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToMany
    private List<OrderItemEntity> orderItems;

    protected OrderEntity() {
    }

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public List<OrderItemEntity> getOrderItems() {
        return orderItems;
    }
    public void setOrderItems(List<OrderItemEntity> orderItems) {
        this.orderItems = orderItems;
    }
}

订单项目:

@Entity
@Table(name = "orders_item")
public class OrderItemEntity {

    @Id
    @Column(name = "orders_item_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    @JoinColumn(name = "product_id", nullable = false, updatable = false)
    private ProductEntity product = new ProductEntity();

    @Column(name = "order_amount")
    private int amount;

    protected OrderItemEntity() {
    }

    public OrderItemEntity(ProductEntity product, int amount) {
        super();
        this.product = product;
        this.amount = amount;
    }
    public int getAmount() {
        return amount;
    }
    public void setAmount(int amount) {
        this.amount = amount;
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public ProductEntity getProduct() {
        return product;
    }
    public void setProduct(ProductEntity product) {
        this.product = product;
    }
}

产品:

@Entity
@Table(name = "product")
public class ProductEntity {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToMany
    private List<OrderItemEntity> orders = new ArrayList<>();

    @Column(name = "name")
    private String name;

    @Column(name = "price")
    private BigDecimal price;

    protected ProductEntity() {
    }

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

    public ProductEntity(String name, BigDecimal price) {
        super();
        this.name = name;
        this.price = price;
    }

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

【问题讨论】:

    标签: hibernate schemagen


    【解决方案1】:
    • orders_orders_item表:

    由于您尚未指定@JoinColumn,因此会创建一个包含两个外键的额外表,而不是仅创建一个外键。

    orders_orders_item (OrderEntity_order_id, orderItems_orders_item_id) 
    

    要解决这个问题,您应该将@JoinColumn 注释添加到OrderEntity。

    @Entity
    @Table(name = "orders")
    public class OrderEntity {
    
        //...
    
        @OneToMany
        @JoinColumn(name = "order_id")
        private List<OrderItemEntity> orderItems;
    }
    

    使用此映射只会将order_id 列添加到orders_item 表中。 orders_orders_item 不会创建不必要的表

    • product_orders_item表:

    orders_item 和 product 之间存在双向关系。您在 orders_item 一侧指定了 @JoinColumn。这导致在orders_item 表上创建product_id 列,这是正确的。

    但另一方面,由于您没有指定 mappedBy,并且它是双向关系,DB 尝试通过创建 product_orders_item 表来建立链接。

    您应该将mappedBy 属性添加到orders 字段。

    @Entity
    @Table(name = "product")
    public class ProductEntity {
    
        // ...
    
        @OneToMany (mappedBy="product")
        private List<OrderItemEntity> orders = new ArrayList<>();
    }
    

    这表明在product 和orders_item 之间已经创建了双向关系(无需映射orders 字段)。无需额外创建表等。感谢@JoinColumn,product_id 列在orders_item 表中创建。

    【讨论】:

      【解决方案2】:

      您的协会:

      @Entity
      public class OrderEntity {
      
          @OneToMany
          private List<OrderItemEntity> orderItems;
      
          // ...
      }
      
      @Entity
      public class ProductEntity {
      
          @OneToMany
          private List<OrderItemEntity> orders = new ArrayList<>();
      
          // ...
      }
      

      是unidirectional@OneToMany。因此,正如文档中所述:

      当使用单向 @OneToMany 关联时,Hibernate 会在两个连接实体之间使用链接表。

      您可以通过添加@Hülya 答案中提到的@JoinColumn 注释来纠正它。 (它是在JPA 2.0 中添加的)。但是bidirectional@OneToMany 在管理集合持久状态时效率更高。每个元素删除只需要一次更新(其中外键列设置为NULL)。

      【讨论】:

        猜你喜欢
        • 2013-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-19
        • 1970-01-01
        • 2020-04-13
        • 1970-01-01
        相关资源
        最近更新 更多