如何为多对多映射的product_tags表创建JPA Repository
你的Product和Tag类通过@ManyToMany注解生成了product_tags中间表,但JPA默认不会为这种无实体的中间表自动生成Repository,下面是两种可行的实现方式:
方案一:创建中间表对应的实体类(支持完整CRUD)
1. 定义复合主键类
因为product_tags的主键是product_id和tag_id的组合,先创建一个可嵌入的主键类:
import jakarta.persistence.Embeddable; import java.io.Serializable; import java.util.Objects; import java.util.UUID; @Embeddable public class ProductTagId implements Serializable { private UUID productId; private UUID tagId; // 必须提供无参构造器 public ProductTagId() {} public ProductTagId(UUID productId, UUID tagId) { this.productId = productId; this.tagId = tagId; } // 复合主键必须重写equals和hashCode @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ProductTagId that = (ProductTagId) o; return Objects.equals(productId, that.productId) && Objects.equals(tagId, that.tagId); } @Override public int hashCode() { return Objects.hash(productId, tagId); } // Getter和Setter方法 public UUID getProductId() { return productId; } public void setProductId(UUID productId) { this.productId = productId; } public UUID getTagId() { return tagId; } public void setTagId(UUID tagId) { this.tagId = tagId; } }
2. 创建ProductTag实体类
对应product_tags表的实体类,关联Product和Tag:
import jakarta.persistence.*; @Entity @Table(name = "product_tags") public class ProductTag { @EmbeddedId private ProductTagId id; @ManyToOne @MapsId("productId") // 关联主键中的productId字段 @JoinColumn(name = "product_id") private Product product; @ManyToOne @MapsId("tagId") // 关联主键中的tagId字段 @JoinColumn(name = "tag_id") private Tag tag; // 无参构造器 public ProductTag() {} public ProductTag(Product product, Tag tag) { this.product = product; this.tag = tag; this.id = new ProductTagId(product.getId(), tag.getId()); } // Getter和Setter方法 public ProductTagId getId() { return id; } public void setId(ProductTagId id) { this.id = id; } public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } public Tag getTag() { return tag; } public void setTag(Tag tag) { this.tag = tag; } }
3. 创建Repository接口
继承JpaRepository即可获得基础CRUD能力,还能自定义查询方法:
import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; import java.util.UUID; public interface ProductTagRepository extends JpaRepository<ProductTag, ProductTagId> { // 根据产品ID查询所有关联的标签关系 List<ProductTag> findByIdProductId(UUID productId); // 根据标签ID查询所有关联的产品关系 List<ProductTag> findByIdTagId(UUID tagId); }
方案二:在现有Repository中通过自定义查询操作中间表(无需实体类)
如果不需要对中间表做完整的CRUD,只是查询或简单操作,可以直接在ProductRepository或TagRepository中添加自定义SQL/JPQL方法:
比如在ProductRepository中添加查询某个产品关联的所有标签ID:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.UUID; public interface ProductRepository extends JpaRepository<Product, UUID> { // 查询产品关联的所有标签ID @Query(value = "SELECT tag_id FROM product_tags WHERE product_id = ?1", nativeQuery = true) List<UUID> findTagIdsByProductId(UUID productId); // 删除产品与标签的关联关系 @Modifying @Transactional @Query(value = "DELETE FROM product_tags WHERE product_id = ?1 AND tag_id = ?2", nativeQuery = true) void removeTagFromProduct(UUID productId, UUID tagId); }
注意:使用@Modifying注解修改数据时,必须配合@Transactional注解。
内容的提问来源于stack exchange,提问作者Ejuku Ikwang'
相关产品推荐
相关产品推荐

