繁体   English   中英

如何使JPQL加入不能使结果翻倍

[英]How to make JPQL joins not double up results

我有一些使用JPA / JPQL和Hibernate引用项目的实体。

一个报价有很多报价项目,每个项目可以有0个或多个调整项。 每种调整都是折扣或附加费,或者是百分比(即商品价格的百分比)或金额(即固定值)

我正在尝试编写一个JPQL查询,该查询将为我提供给定地区,用户和时间段的所有报价的值,并将报价的每个报价项目的价格与任何调整的值相加。 我差一点就可以了,但这不是很正确。

String query = "select q.user, q.contact.parent.region, sum( case " +
        " when a.type = :type_surcharge and a.amountType = :amount_type_percentage then ( a.amount * qi.price ) " +
        " when a.type = :type_surcharge and a.amountType = :amount_type_amount then ( a.amount ) " +
        " when a.type = :type_discount and a.amountType = :amount_type_percentage then ( -1 * a.amount * qi.price ) " +
        " else ( -1 * a.amount ) end ) + sum(qi.price) " +
        " from " + Quote.class.getName() + " q " +
        " left join q.quoteItems qi " +
        " left join qi.adjustments a " +
        " where q.date between :from and :to and q.contact.parent.region in :regions group by q.user, q.contact.parent.region";

问题是,如果报价项目具有多个调整项,则该项目在sum(qi.price)计算中会多次出现

谁能帮我解决此查询,使每个报价项只包括一次? sum( distinct qi.price )不起作用)我希望可以在单个查询中完成。

编辑:这比我想象的要错误的多-即使存在使用左联接(?)的查询,如果存在没有调整的引号,查询的总和将返回null。 唯一正确的数据是:-对一项进行0或1项调整-通过区域/用户/期间过滤器的所有报价中至少对一项进行调整。

实体(简体)

@Entity
@DiscriminatorValue(AbstractCollateral.TYPE_QUOTE)
@Table(name="customer_quote", uniqueConstraints={@UniqueConstraint(name="quote_number_uk", columnNames={"number"})})
public class Quote extends AbstractCollateral<QuotedCarePack>
{
  ... other elements

  @OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval=true)
  protected Set<QuotedCarePack> quoteItems;

}

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="collateral_type", discriminatorType=DiscriminatorType.STRING, length=10)
@Table(name="abstract_collateral")
public abstract class AbstractCollateral<T extends AbstractCollateralItem<?>> extends AbstractManagedData implements ContactInfo{

  private static final long serialVersionUID = 1L;

  public static final String TYPE_ORDER = "order";
  public static final String TYPE_QUOTE = "quote";

  @Column(name="collateral_type", insertable=true, updatable=false, length=10)
  protected String collateralType;

  @ManyToOne(fetch=FetchType.EAGER)
  @JoinColumn(name="customer_contact_id", nullable=false)
  protected CustomerContact contact;

  @ManyToOne(fetch=FetchType.EAGER)
  @JoinColumn(name="user_id", nullable=false)
  protected User user;
  /**
   * The date the collateral was made (not the sent date, necessarily)
   */
  @Column(name="creation_date", nullable=false)
  @Temporal(TemporalType.TIMESTAMP)
  protected Date date;
}

@Entity(name="quoted_care_pack")
public class QuotedCarePack extends AbstractCollateralItem<Quote> {

  private static final long serialVersionUID = 1L;

  @ManyToOne(fetch=FetchType.EAGER)
  @JoinColumn(name="quote_id", nullable=false)
  protected Quote parent;

  @OneToMany(fetch=FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE})
  @JoinTable
  (
      name="quoted_care_pack_adjustment",
      joinColumns={ @JoinColumn(name="quoted_care_pack_id", referencedColumnName="id") },
      inverseJoinColumns={ @JoinColumn(name="adjustment_id", referencedColumnName="id", unique=true) }
  )
  protected Set<Adjustment> adjustments;
}

@Entity(name="adjustment")
public class Adjustment extends AbstractManagedData {

  private static final long serialVersionUID = 1L;

  @Column(name="amount")
  protected double amount;
  @Column(name="reason", length=100)
  protected String reason;
  @Column(name="type")
  @Enumerated(EnumType.STRING)
  protected AdjustmentType type;
  @Column(name="amount_type")
  @Enumerated(EnumType.STRING)
  protected AdjustmentAmountType amountType;
}

不幸的是,JPA不支持select子句中的子查询,这是您需要执行的操作,以使获得所有调整总和的联接不会影响quoteItems的总和。

这样就可以使用本机SQL,或者执行两个查询-一个用于qi.price和,另一个用于调整和:

"select q.user, q.contact.parent.region, sum(qi.price) " +
        " from " + Quote.class.getName() + " q " +
        " left join q.quoteItems qi " +
        " where q.date between :from and :to and q.contact.parent.region in :regions group by q.user, q.contact.parent.region";

"select q.user, q.contact.parent.region, sum( case " +
        " when a.type = :type_surcharge and a.amountType = :amount_type_percentage then ( a.amount * qi.price ) " +
        " when a.type = :type_surcharge and a.amountType = :amount_type_amount then ( a.amount ) " +
        " when a.type = :type_discount and a.amountType = :amount_type_percentage then ( -1 * a.amount * qi.price ) " +
        " else ( -1 * a.amount ) end ) " +
        " from " + Quote.class.getName() + " q " +
        " left join q.quoteItems qi " +
        " left join qi.adjustments a " +
        " where q.date between :from and :to and q.contact.parent.region in :regions group by q.user, q.contact.parent.region";

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM