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