JPA映射疑问:能否通过双列配置mappedBy实现A/B与C的关联?
首先直接给结论:可以实现你的需求,但没法直接在mappedBy中包含两个列——因为mappedBy的作用是指定目标实体类中维护关联的单个属性,而不是直接关联多列。不过我们可以通过其他JPA注解组合来实现多条件(外键列+固定值列)的关联。
下面分两种常见方案来实现:
方案1:单向关联(无需修改C类的关联属性)
这种方式不需要在C类中添加指向A/B的属性,直接在A/B类中定义@OneToMany关联,并通过@Where注解过滤固定的table_name值:
A类的关联配置
@Entity @Table(name = "A") public class A implements Serializable{ private static final long serialVersionUID = 1L; @Id @Column(name = "A_KEY") private String aId; // 关联C:TABLE_KEY匹配aId,且TABLE_NAME='A' @OneToMany @JoinColumn(name = "TABLE_KEY", referencedColumnName = "A_KEY") @Where(clause = "TABLE_NAME = 'A'") private List<C> c; // getter/setter省略 }
B类的关联配置
@Entity @Table(name = "B") public class B implements Serializable{ private static final long serialVersionUID = 1L; @Id @Column(name = "B_KEY") private String bId; // 关联C:TABLE_KEY匹配bId,且TABLE_NAME='B' @OneToMany @JoinColumn(name = "TABLE_KEY", referencedColumnName = "B_KEY") @Where(clause = "TABLE_NAME = 'B'") private List<C> c; // getter/setter省略 }
这种方案的优点是不需要改动C类的结构,查询A/B时会自动带上TABLE_NAME='A'/TABLE_NAME='B'的过滤条件,只返回对应关联的C记录。
方案2:双向关联(在C类中添加指向A/B的属性)
如果需要双向关联(从C也能找到对应的A/B),可以在C类中分别定义指向A和B的@ManyToOne属性,并通过@JoinColumns组合外键列和固定值条件,然后在A/B类中用mappedBy指向这些属性:
C类的关联配置
@Entity @Table(name = "C") public class C implements Serializable{ private static final long serialVersionUID = 1L; @Id @Column(name = "C_KEY") private String cId; @Column(name = "TABLE_KEY") private String tableKey; @Column(name = "TABLE_NAME") private String tableName; // 关联A:TABLE_KEY匹配A的aId,且TABLE_NAME固定为'A' @ManyToOne @JoinColumns({ @JoinColumn(name = "TABLE_KEY", referencedColumnName = "A_KEY"), @JoinColumn(name = "TABLE_NAME", insertable = false, updatable = false, columnDefinition = "VARCHAR(255) DEFAULT 'A'") }) @Where(clause = "TABLE_NAME = 'A'") private A a; // 关联B:TABLE_KEY匹配B的bId,且TABLE_NAME固定为'B' @ManyToOne @JoinColumns({ @JoinColumn(name = "TABLE_KEY", referencedColumnName = "B_KEY"), @JoinColumn(name = "TABLE_NAME", insertable = false, updatable = false, columnDefinition = "VARCHAR(255) DEFAULT 'B'") }) @Where(clause = "TABLE_NAME = 'B'") private B b; // getter/setter省略 }
A类的关联配置
@Entity @Table(name = "A") public class A implements Serializable{ private static final long serialVersionUID = 1L; @Id @Column(name = "A_KEY") private String aId; // 双向关联C,mappedBy指向C类中的a属性 @OneToMany(mappedBy = "a") private List<C> c; // getter/setter省略 }
B类的关联配置
@Entity @Table(name = "B") public class B implements Serializable{ private static final long serialVersionUID = 1L; @Id @Column(name = "B_KEY") private String bId; // 双向关联C,mappedBy指向C类中的b属性 @OneToMany(mappedBy = "b") private List<C> c; // getter/setter省略 }
注意:这种方案下,保存C对象时需要手动设置tableName属性(因为TABLE_NAME列在@JoinColumn中被标记为insertable=false, updatable=false,无法通过关联自动写入),比如关联A时要把C的tableName设为"A",关联B时设为"B"。
关于mappedBy的补充说明
JPA的mappedBy参数只能接受目标实体类中的单个属性名,这个属性通常是@ManyToOne或@OneToOne类型,用来表示关联关系的维护端。它本身不能直接指定多列或固定值条件,只能指向一个已经定义好的关联属性——而那个属性可以通过@JoinColumns来对应数据库中的多列外键(包括固定值列)。
内容的提问来源于stack exchange,提问作者Rax

