如何编写ASS_USER_OFF_LOC表对应的JPA实体类
如何编写ASS_USER_OFF_LOC表对应的JPA实体类
我来帮你一步步实现这个实体类,结合你现有的实体结构和目标表的约束,下面是具体的方案和代码:
首先,先明确目标表的核心特性:
- 主键是
USER列(对应用户表的USER_ID),意味着每个用户只能有一条关联记录 - 外键
OFFICE和LOCAL联合关联到ASS_OFF_LOC表的复合主键(CODE_OFFICE和CODE_LOCAL) - 三个字段都不允许为NULL
实体类实现方案
我们可以创建名为AssUserOffLoc的实体类,下面是完整代码,同时我会逐段解释关键注解的作用:
import jakarta.persistence.*; import java.io.Serializable; import java.util.Objects; @Entity @Table(name = "ASS_USER_OFF_LOC") public class AssUserOffLoc implements Serializable { private static final long serialVersionUID = 1L; // 方案1:直接将User作为主键(符合表的主键约束,每个用户一条记录) @Id @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "USER", nullable = false, updatable = false) private User user; // 关联到AssOffLoc实体(通过联合外键OFFICE和LOCAL) @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumns({ @JoinColumn( name = "OFFICE", referencedColumnName = "CODE_OFFICE", nullable = false ), @JoinColumn( name = "LOCAL", referencedColumnName = "CODE_LOCAL", nullable = false ) }) private AssOffLoc assOffLoc; // 无参构造方法(JPA要求必须提供) public AssUserOffLoc() { super(); } // 便捷构造方法:通过User和AssOffLoc实例创建 public AssUserOffLoc(User user, AssOffLoc assOffLoc) { this.user = user; this.assOffLoc = assOffLoc; } // Getter和Setter public User getUser() { return user; } // 用户主键不允许修改,所以setUser可以做限制,或者直接不提供(根据业务需求) public void setUser(User user) { // 因为主键不可修改,所以如果当前已有用户,不允许替换 if (this.user != null) { throw new IllegalStateException("用户关联不可修改"); } this.user = user; } public AssOffLoc getAssOffLoc() { return assOffLoc; } public void setAssOffLoc(AssOffLoc assOffLoc) { this.assOffLoc = assOffLoc; } // equals和hashCode:基于主键User(因为每个用户唯一一条记录) @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AssUserOffLoc that = (AssUserOffLoc) o; return Objects.equals(user, that.user); } @Override public int hashCode() { return Objects.hash(user); } }
关键部分解释
主键设计:
直接使用User实体作为@Id,完美匹配表的主键约束(每个用户仅一条记录)。updatable = false确保主键不会被意外修改,fetch = FetchType.LAZY启用懒加载,避免不必要的用户数据查询。关联AssOffLoc实体:
因为AssOffLoc的主键是复合键(办公室编码+本地编码),所以用@JoinColumns指定两个外键列:OFFICE列关联到ASS_OFF_LOC表的CODE_OFFICELOCAL列关联到ASS_OFF_LOC表的CODE_LOCAL
这样JPA就能正确识别联合外键,关联到AssOffLoc实体。
约束与业务规则:
optional = false和nullable = false对应表中的非空约束setUser方法中添加了修改限制,符合“用户主键不可变更”的业务逻辑(因为每个用户只能有一条记录,一旦关联就不能换用户)
备选方案(显式映射用户ID主键)
如果你更倾向于直接映射数据库的USER列作为主键(而非实体对象),可以用下面的写法,核心逻辑一致:
@Entity @Table(name = "ASS_USER_OFF_LOC") public class AssUserOffLoc implements Serializable { private static final long serialVersionUID = 1L; @Id @Column(name = "USER", nullable = false, updatable = false) private long userId; @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "USER", insertable = false, updatable = false, nullable = false) private User user; @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumns({ @JoinColumn(name = "OFFICE", referencedColumnName = "CODE_OFFICE", nullable = false), @JoinColumn(name = "LOCAL", referencedColumnName = "CODE_LOCAL", nullable = false) }) private AssOffLoc assOffLoc; // 无参构造方法 public AssUserOffLoc() { super(); } // 便捷构造方法 public AssUserOffLoc(long userId, AssOffLoc assOffLoc) { this.userId = userId; this.assOffLoc = assOffLoc; } // Getter和Setter public long getUserId() { return userId; } public void setUserId(long userId) { if (this.userId != 0) { throw new IllegalStateException("用户ID不可修改"); } this.userId = userId; } public User getUser() { return user; } public void setUser(User user) { if (user != null) { this.userId = user.getUserId(); } this.user = user; } public AssOffLoc getAssOffLoc() { return assOffLoc; } public void setAssOffLoc(AssOffLoc assOffLoc) { this.assOffLoc = assOffLoc; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AssUserOffLoc that = (AssUserOffLoc) o; return userId == that.userId; } @Override public int hashCode() { return Objects.hash(userId); } }
这种写法中,userId作为显式主键,user字段仅做关联查询用(insertable = false, updatable = false避免重复维护)。
备注:内容来源于stack exchange,提问作者paniko
相关产品推荐
相关产品推荐

