【问题标题】:Criteria API Specification - Filter records and return only the latest record for many to one mappings标准 API 规范 - 过滤记录并仅返回多对一映射的最新记录
【发布时间】:2021-01-24 04:54:22
【问题描述】:

我有两个表,Lead 和 LeadActivity。一个潜在客户可以有许多潜在客户活动,并且映射是通过 @ManyToOne 从 LeadActivity 到 Lead 完成的。

问题陈述 - 我想过滤 LeadActivity 记录,如果有多个具有相同leadId的leadactivity记录,我应该只得到一个最新的记录(具有最大主键)。谁能指导我在这种情况下如何编写规范或标准 API?我知道这可以通过其他方式实现,但我必须使用规范 API。下面是实体类

领导

@Entity
@Table(name = "customer_lead")
@Where(clause = ReusableFields.SOFT_DELETED_CLAUSE)
@Audited(withModifiedFlag = true)
@Data
public class Lead extends ReusableFields implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "lead_id", updatable = false, nullable = false)
    Long leadId;

    @Column(name = "name")
    String customerName;

    @Column(name = "primary_mobile")
    String primaryMobile;

    @Column(name = "secondary_mobile")
    String secondaryMobile;

    //more fields
}

领导活动

@Entity
@Table(name = "LeadActivity")
@Data
@Where(clause = ReusableFields.SOFT_DELETED_CLAUSE)
public class LeadActivity extends ReusableFields implements Serializable
{
@Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "leadactivity_id", updatable = false, nullable = false)
    Long leadActivityId;

    @Column(name = "activity_date_time", nullable = false)
    @NonNull
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
    Date activityDateTime;

    @Column(name = "title")
    @NonNull
    String title;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "lead_id", nullable = false)
    @JsonIgnoreProperties(
    { "hibernateLazyInitializer", "handler" })
    @NotFound(action = NotFoundAction.IGNORE)
    Lead lead;

//More fields
}

预期输出 - 假设存在两个具有相同leadId 的记录。我只想根据他们的 id 获取其中最新的。 id 较低的应该被忽略

【问题讨论】:

    标签: spring-boot spring-data-jpa criteria criteria-api criteriaquery


    【解决方案1】:

    试试这个:

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<LeadActivity> cq = cb.createQuery(LeadActivity.class);
    
    Root<LeadActivity> rootLeadActivity = cq.from(LeadActivity.class);
    Join<LeadActivity,Lead> joinLead = rootLeadActivity.join(LeadActivity_.lead,JoinType.INNER);
    
    /* If you dont use metamodel: 
     * Join<LeadActivity,Lead> joinLead = rootLeadActivity.join("lead",JoinType.INNER);
     */
    
    // For performance, if you use JPA 2.1 set the leader id condition in the join
    joinLead.on(cb.equal(joinLead.get(Lead_.leadId),LEAD_ID));
    
    List<Predicate> predicatesList= new ArrayList<>();
    /* if you use version 2.0 you will have to put it in the where 
     * predicatesList.add(cb.equal(joinLead.get(Lead_.leadId),LEAD_ID));
     */
    
    Subquery<Long> sqMaxId = cq.subquery(Long.class);
    Root<LeadActivity> sqRootActivity = sqMaxId.from(LeadActivity.class);
    Join<LeadActivity,Lead> sqJoinLead = sqRootActivity.join(LeadActivity_.lead,JoinType.INNER);
    sqMaxId.where(cb.equal(sqJoinLead.get(Lead_.leadId),joinLead.get(Lead_.leadId)));
    sqMaxId.select(cb.max(sqRootActivity.get(LeadActivity_.leadActivityId)));
    
    predicatesList.add(cb.equal(rootLeadActivity.get(LeadActivity_.leadActivityId),sqMaxId.getSelection()));
    
    cq.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
    cq.multiselect(rootLeadActivity);
    

    结果查询:

    select a.* from lead_activity a
    inner join lead l on a.lead_id = l.lead_id and l.lead_id = LEAD_ID
    where a.lead_activity_id = 
        (select max(lead_activity_id) from lead_activity where lead_id = LEAD_ID)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-06
      • 1970-01-01
      • 2013-08-25
      • 2016-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多