如何使JPQL连接不会使结果加倍

时间:2014-06-13 15:39:53

标签: java hibernate jpa jpql

我有几个实体用于引用项目,使用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";

问题是如果报价项目有多个调整,那么该项目在总和(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;
}

0 个答案:

没有答案