用JoinColumn使用JPA的OneToMany不自动生成数据库表

本文介绍了在ORM中如何正确配置一对多的关系,避免不必要的关联表生成,并提供了具体的代码示例。

有两个实体Order和Customer,一个用户可以有多个订单,一个订单属于一个用户,所以Customer与Order是一对多的关系,那么在Order实体里可以有一个到Customer的引用customer,同时在Customer里有一个Order实体的集合orders。如果在只是如下这样写:

public class Order {
    @id
    private long id;
    @ManyToOne
    private Customer customer;

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

    public long getId() {
        return this.id;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Customer getCustomer() {
        return this.customer;
    }
}

public class Customer {
    @id
    private long id;
    @OneToMany
    private Set<Order> orders;

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

    public long getId() {
        return this.id;
    }

    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }

    public Set<Order> getOrders() {
        return this.orders;
    }
}

那么系统可能会自动生成一张Customer_Order关联表,可是事实上我们不需要这样的表,因为通过 Select order from Order order where order.customer.id=:id, 就可以找到某个Customer的Orders,而不需要另建一张表。要想去掉这个自动生成的表,要这样写:

public class Order {
    @id
    private long id;
    @ManyToOne
    @JoinColumn(name = "customer", nullable = false)
    private Customer customer;

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

    public long getId() {
        return this.id;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Customer getCustomer() {
        return this.customer;
    }
}

public class Customer {
    @id
    private long id;
    @OneToMany(mappedBy = "customer")
    private Set<Order> orders;

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

    public long getId() {
        return this.id;
    }

    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }

    public Set<Order> getOrders() {
        return this.orders;
    }
} 

多出一个mappedBy和JoinColumn, 就是告诉JPA实现者,orders是通过order里的customer映射来的,每次查找orders通过Order里的customer联接。这样就不会生成Customer_Order关联表了

转载于:https://my.oschina.net/komodo/blog/919059

### 一对多关联的注解配置方式 在 JPA 中,实现一对多(OneToMany)关联通常使用 `@OneToMany` 注解,并结合 `@JoinColumn` 来指定外键字段。`@OneToMany` 注解可以用于字段或方法上,用于定义主实体与从实体之间的关系。例如,一个 `User` 实体拥有多条 `Order` 记录时,可以如下配置: ```java @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "user_id") // 指定外键字段 private List<Order> orders = new ArrayList<>(); // Getter and Setter } ``` ```java @Entity public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String product; // 需要显式声明 @ManyToOne,因为关系由 User 端管理 // Getter and Setter } ``` 通过 `@JoinColumn(name = "user_id")` 指定外键列名,该外键列将存储 `User` 的主键值。这种配置方式适用于单向的一对多关系,即 `User` 管理关联关系,而 `Order` 需要显式引用 `User` [^1]。 ### 双向一对多关联的实现 在某些场景下,可能需要双向访问关联对象,例如从 `Order` 对象中访问所属的 `User`。此时需要在 `Order` 端使用 `@ManyToOne` 注解,并通过 `mappedBy` 属性指定由哪一方管理关联关系: ```java @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user") private List<Order> orders = new ArrayList<>(); // Getter and Setter } ``` ```java @Entity public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String product; @ManyToOne @JoinColumn(name = "user_id") private User user; // Getter and Setter } ``` 在这种配置中,`mappedBy = "user"` 示关联关系由 `Order` 实体中的 `user` 字段维护。因此,`User` 实体直接管理外键,而是由 `Order` 端负责设置和更新外键值 [^1]。 ### 使用 `orphanRemoval` 控制关联对象删除行为 `orphanRemoval` 是 `@OneToMany` 注解中的一个可选参数,用于控制当主实体中移除某个关联对象时,是否删除该对象。例如,当从 `User` 的 `orders` 列中移除一个 `Order` 时,如果设置了 `orphanRemoval = true`,则该 `Order` 将被自动删除: ```java @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user") private List<Order> orders = new ArrayList<>(); ``` 该参数适用于需要级联删除的场景,但需要注意外键是否允许为 `NULL`,否则可能会导致约束异常。此外,`orphanRemoval` 与 `mappedBy` 配合使用时,应确保外键字段允许更新,以避免执行删除操作时出现异常 [^2]。 ### 集合类型的选择:List 与 Set 在一对多关系中,可以选择使用 `List` 或 `Set` 来存储关联对象。使用 `List` 可以保持插入顺序,而 `Set` 则确保集合中对象的唯一性。在 JPA 实现中,`Set` 更适合用于避免重复记录,但 Hibernate 对 `Set` 和 `List` 的处理方式有所同: ```java @OneToMany private Set<Order> orders = new HashSet<>(); ``` 如果希望使用 `Set`,则需要确保 `Order` 类实现 `equals()` 和 `hashCode()` 方法,以便正确判断对象是否重复。而使用 `List` 时,JPA 会通过索引字段维护顺序,但可能会引入额外的性能开销 [^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值