如何使用Hibernate在实体类B中构建来自TA表的<Key,Value>映射?
嘿,这个需求在Hibernate里其实有两种常用的实现方式,我给你拆解清楚,你可以根据自己的场景来选:
方式一:使用@OneToMany + @MapKey(适合TA是独立实体的场景)
如果你的TA表除了key、value和外键之外,还有其他业务字段,或者需要单独对TA表的数据进行CRUD操作,那可以把TA映射成独立实体A,再通过一对多关联到实体B,同时用@MapKey指定Map的键来源。
实体类A(对应TA表)
因为每个B实例对应的TA记录中,key应该是唯一的,所以TA的主键需要是联合主键(外键id + key):
@Entity @Table(name = "TA") public class A { // 嵌入式联合主键 @EmbeddedId private AId id; @Column(name = "value") private String value; // 关联到实体B,MapsId用来映射联合主键中的bId字段 @ManyToOne @MapsId("bId") @JoinColumn(name = "id") // TA的id字段是TB的外键 private B b; // 嵌入式主键类,必须实现Serializable接口 @Embeddable public static class AId implements Serializable { @Column(name = "id") private Long bId; @Column(name = "key") private String key; // 必须实现equals和hashCode方法,以及无参/全参构造器 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AId aId = (AId) o; return Objects.equals(bId, aId.bId) && Objects.equals(key, aId.key); } @Override public int hashCode() { return Objects.hash(bId, key); } } // getter、setter方法 }
实体类B(对应TB表)
在B中定义Map集合,通过@OneToMany关联A实体,用@MapKey指定用A的key字段作为Map的键:
@Entity @Table(name = "TB") public class B { @Id @Column(name = "id") private Long id; // 其他业务字段... // 映射TA表的键值对集合,mappedBy指向A实体中的b属性 @OneToMany(mappedBy = "b", fetch = FetchType.LAZY) @MapKey(name = "key") // 用A实体的key字段作为Map的键 private Map<String, A> aMap = new HashMap<>(); // 如果你需要直接拿到<String, String>类型的Map,可以加一个@Transient的转换方法 @Transient public Map<String, String> getKeyValueMap() { return aMap.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); } // getter、setter方法 }
方式二:使用@ElementCollection(适合TA仅存储键值对的场景)
如果TA表只是用来存储B的键值对,不需要单独操作这些记录,那可以用@ElementCollection直接把TA表映射成B的一个Map集合,不需要创建A实体,实现更简洁。
实体类B(对应TB表)
@Entity @Table(name = "TB") public class B { @Id @Column(name = "id") private Long id; // 其他业务字段... // 直接映射TA表为<String, String>的Map @ElementCollection(fetch = FetchType.LAZY) @CollectionTable(name = "TA", joinColumns = @JoinColumn(name = "id")) // 关联TB的id字段 @MapKeyColumn(name = "key") // TA的key字段作为Map的键 @Column(name = "value") // TA的value字段作为Map的值 private Map<String, String> keyValueMap = new HashMap<>(); // getter、setter方法 }
使用示例
不管用哪种方式,查询B的时候Hibernate都会自动执行类似你写的SQL,关联TA表获取键值对:
// 用EntityManager查询指定id的B实例 B b = entityManager.find(B.class, 1L); // 获取键值对Map Map<String, String> kvMap = b.getKeyValueMap(); // 方式一 // 或者方式二直接获取 // Map<String, String> kvMap = b.getKeyValueMap();
两种方式的区别:
- 方式一适合TA表有额外业务逻辑的场景,灵活性更高;
- 方式二更简洁,适合TA仅作为B的附属键值存储的场景。
内容的提问来源于stack exchange,提问作者Nidhi Hassan
相关产品推荐
相关产品推荐

