You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JPA查询:匹配无关联实体多对多属性查询指定租户关联的所有Item

实体定义

你提供的三个JPA实体代码如下:

@Entity
public class Item {
    [...]
    @ManyToOne(optional = false) 
    @JoinColumn(nullable = false)
    private ItemDescriptor asset;
    [...]
}

@Entity
public class ItemDescriptor {
    [...]
    @ManyToMany(fetch = FetchType.LAZY)
    private Set<ContentPlan> contentPlans;
    [...]
}

@Entity
public class Tenant {
    [...]
    @ManyToMany
    private Set<ContentPlan> contentPlans;
    [...]
}
查询需求

给定指定租户Tenant t,查询所有符合以下条件的Item i:i关联的ItemDescriptor的contentPlans集合中,至少有一个元素属于t的contentPlans范围。

实现方案

方案1:Spring Data JPA 派生查询(最简单,无需手动写JPQL)

直接在Item对应的Repository接口中添加如下方法,传入租户的contentPlans集合即可:

// 自动去重,避免多对多关联返回重复Item
List<Item> findDistinctByAsset_ContentPlansIn(Set<ContentPlan> tenantContentPlans);

调用示例:

Tenant t = // 你获取到的指定租户实例
List<Item> items = itemRepository.findDistinctByAsset_ContentPlansIn(t.getContentPlans());

方案2:自定义JPQL查询

如果需要更灵活的查询逻辑,可以用@Query注解写JPQL:

@Query("SELECT DISTINCT i FROM Item i " +
        "JOIN i.asset a " +
        "JOIN a.contentPlans cp " +
        "WHERE cp IN :tenantContentPlans")
List<Item> findItemsByTenantContentPlans(@Param("tenantContentPlans") Set<ContentPlan> tenantContentPlans);

如果直接传入Tenant实例作为参数,也可以结合SpEL简化写法:

@Query("SELECT DISTINCT i FROM Item i " +
        "JOIN i.asset a " +
        "JOIN a.contentPlans cp " +
        "WHERE cp IN :#{#tenant.contentPlans}")
List<Item> findItemsByTenant(@Param("tenant") Tenant tenant);

方案3:Criteria API 实现(适用于动态查询场景)

如果查询条件是动态拼接的,可以用Criteria API实现:

public List<Item> findItemsByTenant(Tenant tenant) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Item> query = cb.createQuery(Item.class);
    Root<Item> itemRoot = query.from(Item.class);
    // 关联ItemDescriptor
    Join<Item, ItemDescriptor> assetJoin = itemRoot.join("asset");
    // 关联contentPlans
    Join<ItemDescriptor, ContentPlan> cpJoin = assetJoin.join("contentPlans");

    // 筛选条件:contentPlan在租户的contentPlans范围内
    query.where(cpJoin.in(tenant.getContentPlans()))
            .distinct(true); // 去重

    return entityManager.createQuery(query).getResultList();
}
注意事项
  • 所有方案都加了DISTINCT,是因为多对多关联查询时,如果一个Item对应的ItemDescriptor有多个符合条件的ContentPlan,会返回多条重复的Item记录,去重后可以避免这个问题。
  • 如果你的需求是Item关联的ItemDescriptor的所有contentPlans都属于租户的contentPlans,只需要把查询逻辑调整为NOT EXISTS (SELECT cp FROM a.contentPlans cp WHERE cp NOT IN :tenantContentPlans)即可。

内容的提问来源于stack exchange,提问作者Marcus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 08:36:03