- https://www.baeldung.com/jpa-join-column
- https://docs.oracle.com/javaee/6/api/javax/persistence/JoinColumn.html
- https://stackoverflow.com/questions/37542208/what-is-joincolumn-and-how-it-is-used-in-hibernate
在 JPA 中,通过外键自动获取关联对象的值通常使用关系映射注解(如 @ManyToOne)来实现。以下是针对 am_application 表的外键关联实现:
1. 首先创建被关联的实体 AmSubscriber
- import jakarta.persistence.*;
- import lombok.Getter;
- import lombok.Setter;
- import java.time.LocalDateTime;
- @Getter
- @Setter
- @Entity
- @Table(name = "am_subscriber")
- public class AmSubscriber {
-
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name = "SUBSCRIBER_ID")
- private Integer subscriberId;
-
- @Column(name = "USER_ID", length = 64)
- private String userId;
-
- @Column(name = "TENANT_ID")
- private Integer tenantId;
-
- @Column(name = "EMAIL_ADDRESS", length = 256)
- private String emailAddress;
-
- @Column(name = "DATE_SUBSCRIBED")
- private LocalDateTime dateSubscribed;
-
- // 其他字段...
- }
复制代码 2. 在 AmApplication 中添加关联关系
- import jakarta.persistence.*;
- import lombok.Getter;
- import lombok.Setter;
- import org.hibernate.annotations.CreationTimestamp;
- import org.hibernate.annotations.UpdateTimestamp;
- import java.time.LocalDateTime;
- @Getter
- @Setter
- @Entity
- @Table(name = "am_application",
- uniqueConstraints = {
- @UniqueConstraint(name = "uk_app_name_subscriber_org", columnNames = {"name", "subscriber", "organization"}),
- @UniqueConstraint(name = "uk_app_uuid", columnNames = "uuid")
- },
- indexes = {
- @Index(name = "idx_subscriber_id", columnList = "subscriber_id"),
- @Index(name = "idx_aa_at_cb", columnList = "applicationTier, createdBy")
- })
- public class AmApplication {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name = "APPLICATION_ID")
- private Integer applicationId;
- @Column(name = "NAME", length = 100)
- private String name;
- // 关键:使用 @ManyToOne 建立外键关联
- @ManyToOne(fetch = FetchType.LAZY) // 推荐使用懒加载
- @JoinColumn(name = "SUBSCRIBER_ID", referencedColumnName = "SUBSCRIBER_ID")
- private AmSubscriber subscriber;
- // 其他字段保持不变...
- @Column(name = "APPLICATION_TIER", length = 50, columnDefinition = "varchar(50) default 'Unlimited'")
- private String applicationTier = "Unlimited";
-
- // ... (其他字段)
- }
复制代码 关键注解说明:
- @ManyToOne:
- 表示多对一关系(多个应用对应一个订阅者)
- fetch = FetchType.LAZY:推荐使用懒加载,只在需要时加载关联对象
- @JoinColumn:
- name = "SUBSCRIBER_ID":指定当前表中的外键列名
- referencedColumnName = "SUBSCRIBER_ID":指定目标表的主键列名
使用示例:
保存新应用(自动关联订阅者)
- // 先获取订阅者
- AmSubscriber subscriber = subscriberRepository.findById(123).orElseThrow();
- // 创建新应用并关联订阅者
- AmApplication app = new AmApplication();
- app.setName("PaymentApp");
- app.setSubscriber(subscriber); // 设置关联对象
- app.setOrganization("finance");
- // 保存时会自动处理外键关系
- applicationRepository.save(app);
复制代码 查询应用并获取关联对象
- // 查询应用
- AmApplication app = applicationRepository.findById(456).orElseThrow();
- // 获取关联的订阅者信息(懒加载,首次访问时查询)
- System.out.println("订阅者ID: " + app.getSubscriber().getSubscriberId());
- System.out.println("订阅者邮箱: " + app.getSubscriber().getEmailAddress());
复制代码 JPQL 查询(自动关联)
- @Query("SELECT a FROM AmApplication a " +
- "JOIN FETCH a.subscriber s " + // 使用JOIN FETCH避免N+1查询
- "WHERE a.organization = :org")
- List findByOrgWithSubscriber(@Param("org") String organization);
复制代码 自定义查询方法
- public interface AmApplicationRepository extends JpaRepository {
-
- // 通过订阅者邮箱查找应用
- List findBySubscriberEmailAddress(String email);
-
- // 通过订阅者ID查找应用
- List findBySubscriberSubscriberId(Integer subscriberId);
- }
复制代码 处理双向关系(可选)
如果需要在订阅者端反向访问应用列表,可以添加双向映射:- // 在 AmSubscriber 类中添加
- @OneToMany(mappedBy = "subscriber", cascade = CascadeType.ALL)
- private List applications = new ArrayList<>();
- // 在 AmApplication 中保持关联时同步更新
- public void setSubscriber(AmSubscriber subscriber) {
- this.subscriber = subscriber;
- if (subscriber != null && !subscriber.getApplications().contains(this)) {
- subscriber.getApplications().add(this);
- }
- }
复制代码 保留两个外键字段
- 保留subscriber_id字段
- 保留subscriber对象字段
- insertable = false, updatable = false属性是关键
- public class AmApplication {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name = "APPLICATION_ID")
- private Integer applicationId;
- @Column(name = "NAME", length = 100)
- private String name;
- // 关键:使用 @ManyToOne 建立外键关联
- @ManyToOne(fetch = FetchType.LAZY) // 推荐使用懒加载
- @JoinColumn(name = "当前表字段SUBSCRIBER_ID", referencedColumnName = "父表字段SUBSCRIBER_ID", insertable = false, updatable = false)
- private AmSubscriber subscriber;
-
- Column(name="SUBSCRIBER_ID")
- private String SUBSCRIBER_ID;
复制代码 注意事项:
- 避免循环引用:
- 使用 @JsonIgnore 防止 JSON 序列化无限循环
- @OneToMany(mappedBy = "subscriber")
- @JsonIgnore
- private List applications;
复制代码 - N+1 查询问题:
- @EntityGraph(attributePaths = "subscriber")
- List findByOrganization(String org);
复制代码 - 更新操作:
- // 更改应用的订阅者
- AmSubscriber newSub = subscriberRepository.findById(789).orElseThrow();
- app.setSubscriber(newSub);
- applicationRepository.save(app); // 自动更新外键
复制代码 - 删除策略:
- 默认 @ManyToOne 使用 FetchType.EAGER
- 推荐显式设置 fetch = FetchType.LAZY
- 删除订阅者时需先处理关联应用(或使用级联删除)
这样配置后,JPA 会自动处理外键关系,在访问 AmApplication 的 subscriber 属性时,会通过外键 SUBSCRIBER_ID 自动加载关联的 AmSubscriber 对象。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |