【问题标题】:How to query for entities by their collection value如何通过集合值查询实体
【发布时间】:2012-05-22 19:30:43
【问题描述】:

我正在使用 jpa,我有以下实体:

@Entity
@Table(name="favorites_folders")
public class FavoritesFolder {

     private static final long serialVersionUID = 1L;

     @Id
     private String id;

     @NotNull
     @Size(min = 1, max = 50)
     public String name;

     @ElementCollection(fetch = FetchType.LAZY)
     @CollectionTable(
        name="favorites_products",
        joinColumns=@JoinColumn(name="folder_id")
        )
     @Column(name="product_id")
     @NotNull
     private Set<String> productsIds = new HashSet<String>();
}

我想要做的是获得一组FavoritesFolder 实体,它们在其productsIds 成员集中包含字符串“favorite-id”。

有谁知道如何在 criteria api 中完成?

更新:
我在想下面的 sql 应该可以解决问题,但我不确定如何在 JPQLCriteria API 中做到这一点:

select * from favorites_folders join favorites_products on favorites_folders.id = favorites_products.folder_id where favorites_products.product_id = 'favorite-id'

【问题讨论】:

    标签: jpa collections criteria-api


    【解决方案1】:

    要使用标准 api 在其 productsIds 成员集中获取一组包含字符串“favorite-id”的收藏夹实体,您应该执行以下操作:

    CriteriaBuilder cb = em.getCriteriaBuilder(); //em is EntityManager
    CriteriaQuery<FavoritesFolder> cq = cb.createQuery(FavoritesFolder.class);
    Root<FavoritesFolder> root = cq.from(FavoritesFolder.class);
    
    Expression<Collection<String>> productIds = root.get("productsIds");
    Predicate containsFavoritedProduct = cb.isMember("favorite-id", productIds);
    
    cq.where(containsFavoritedProduct);
    
    List<FavoritesFolder> favoritesFolders = em.createQuery(cq).getResultList();
    

    更多关于Collections in JPQL and Criteria Queries的信息。

    【讨论】:

    • 我知道在这个主题中我们引用的是 ID,因此它们必须是 EQUAL 才能匹配,但是假设我们有一个 Collection&lt;String&gt;,我们可以做本质上相同的事情,而不是需要一个项目是equal,我们可以使用LIKE 来匹配一个项目?
    • @domnicbri7 在相关的question 上我找到了解决方案。在 Root 类上使用 join 方法cb.like(from.join("apples").get("color"), textParameter)
    【解决方案2】:

    使用 IN 的另一种方式

    @Entity
    public class UserCategory implements Serializable {
    private static final long    serialVersionUID    = 8261676013650495854L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @ElementCollection
    private List<String> categoryName;
    
    
    (...)
    }
    

    然后你可以写一个像这样的条件查询

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<UserCategory> q = cb.createQuery(UserCategory.class);
        Root<UserCategory> root = q.from(UserCategory.class);
    
        Predicate predicate = cb.conjunction();
        Predicate p1 = cb.equal(root.get(UserCategory_.targetSiteType), siteType.getName());
        Predicate p2 = root.get(UserCategory_.categoryName).in(category);
        predicate = cb.and(p1,p2);
    
        q.where(predicate);
    
        TypedQuery<UserCategory> tq = entityManager.createQuery(q);
        List<UserCategory> all = tq.getResultList();
    
        if (all == null || all.size() == 0){
            return null;
        }else if (all.size() > 1){
            throw new Exception("Unexpected result - "+all.size());
        }else{
            return all.get(0);
        }
    

    【讨论】:

      【解决方案3】:

      这是我的工作。 我正在使用 Springboot 1.5.9。我没有时间找出根本原因。我所知道的是,当通过JacksonMappingAwareSortTranslator 时,这种嵌套属性被忽略了。 所以我为解决这个问题所做的不是使用由解析器创建的 Sort 对象。 这是我在Kotlin 中的代码。如果不这样做,pageable.sort 就是null,并且排序不起作用。我的代码将创建一个新的 PageRequest 对象,该对象具有非空的 sort 有效。

          @RequestMapping("/searchAds", method = arrayOf(RequestMethod.POST))
          fun searchAds(
              @RequestBody cmd: AdsSearchCommand,
              pageable: Pageable,
              resourceAssembler: PersistentEntityResourceAssembler,
              sort: String? = null
          ): ResponseEntity<PagedResources<Resource<Ads>>> {
              val page = adsService.searchAds(cmd, pageable.repairSortIfNeeded(sort))
              resourceAssembler as ResourceAssembler<Ads, Resource<Ads>>
              return adsPagedResourcesAssembler.toResource(page, resourceAssembler).toResponseEntity()
          }
      
          fun Pageable.repairSortIfNeeded(sort: String?): Pageable {
              return if (sort.isNullOrEmpty() || this.sort != null) {
                  this
              } else {
                  sort as String
                  val sa = sort.split(",")
                  val direction = if (sa.size > 1) Sort.Direction.valueOf(sa[1]) else Sort.Direction.ASC
                  val property = sa[0]
                  PageRequest(this.pageNumber, this.pageSize, direction, property)
              }
          }
      

      【讨论】:

        猜你喜欢
        • 2012-04-17
        • 1970-01-01
        • 2019-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-26
        • 1970-01-01
        相关资源
        最近更新 更多