基于多对多关系检索所选列,该关系与使用JPA条件的联接表中的额外列一起表示

基于多对多关系检索所选列,该关系与使用JPA条件的联接表中的额外列一起表示,jpa,many-to-many,jpa-2.0,criteria,criteria-api,Jpa,Many To Many,Jpa 2.0,Criteria,Criteria Api,我在MySQL数据库中有三个表 zone_table zone_id (PK) zone_name transporter_id (FK references the transporter table - unrelated here). 由于zone_表和weight之间的多对多关系由zone_charge表表示,表中有一个额外的列(即charge),因此创建了一个表示复合主键的可嵌入类ZoneChargePK 使用此关系,我需要从weight表中检索由三个字段组成的行列表,weig

我在MySQL数据库中有三个表

zone_table

zone_id (PK)
zone_name
transporter_id (FK references the transporter table - unrelated here).


由于
zone_表
weight
之间的多对多关系由
zone_charge
表表示,表中有一个额外的列(即
charge
),因此创建了一个表示复合主键的可嵌入类
ZoneChargePK

使用此关系,我需要从
weight
表中检索由三个字段组成的行列表,
weight\u id
weight
,并从
zone\u charge
表中检索给定区域的
charge

本机SQL如下所示

SELECT w.weight_id, w.weight, zc.charge
FROM weight w
LEFT OUTER JOIN zone_charge zc ON w.weight_id=zc.weight_id
WHERE zc.zone_id=?
ORDER BY w.weight ASC
相应的JPQL如下所示

SELECT w.weightId, w.weight, zc.charge 
FROM Weight w 
LEFT JOIN w.zoneChargeSet zc 
WITH zc.zone.zoneId=:id 
ORDER BY w.weight
我希望JPA criteria查询能够表达同样的内容,因为这个查询反过来会动态生成。我留下了以下不完整的查询条件

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createTupleQuery();
Root<Weight> root = criteriaQuery.from(entityManager.getMetamodel().entity(Weight.class));

SetJoin<Weight, ZoneCharge> join = root.join(Weight_.zoneChargeSet, JoinType.LEFT);
criteriaQuery.multiselect(root.get(Weight_.weightId), root.get(Weight_.weight), join.get(ZoneCharge_.zoneTable));
TypedQuery<Tuple> typedQuery = entityManager.createQuery(criteriaQuery);
List<Tuple> tuples = typedQuery.getResultList();
其实应该是,

select
    weight0_.weight_id as col_0_0_,
    weight0_.weight as col_1_0_,
    zonecharge1_.charge as col_2_0_        
from
    social_networking.weight weight0_ 
left outer join
    social_networking.zone_charge zonecharge1_ 
        on weight0_.weight_id=zonecharge1_.weight_id
除了
where
orderby
之外。那么,实际的条件查询是什么样子的呢


编辑:

分区表
实体(仅在需要时):


ZoneCharge
实体:

@Entity
@Table(name = "weight", catalog = "social_networking", schema = "", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"weight_id"})})
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Weight.findAll", query = "SELECT w FROM Weight w"),
    @NamedQuery(name = "Weight.findByWeightId", query = "SELECT w FROM Weight w WHERE w.weightId = :weightId"),
    @NamedQuery(name = "Weight.findByWeight", query = "SELECT w FROM Weight w WHERE w.weight = :weight")})
public class Weight implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "weight_id", nullable = false)
    private Long weightId;
    @Column(name = "weight", precision = 35, scale = 2)
    private BigDecimal weight;



    @OneToMany(cascade = CascadeType.ALL, mappedBy = "weight", fetch = FetchType.LAZY)
    private Set<ZoneCharge> zoneChargeSet;    //<-------------------------
}
@Entity
@Table(name = "zone_charge", catalog = "social_networking", schema = "")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "ZoneCharge.findAll", query = "SELECT z FROM ZoneCharge z"),
    @NamedQuery(name = "ZoneCharge.findByZoneId", query = "SELECT z FROM ZoneCharge z WHERE z.zoneChargePK.zoneId = :zoneId"),
    @NamedQuery(name = "ZoneCharge.findByWeightId", query = "SELECT z FROM ZoneCharge z WHERE z.zoneChargePK.weightId = :weightId"),
    @NamedQuery(name = "ZoneCharge.findByCharge", query = "SELECT z FROM ZoneCharge z WHERE z.charge = :charge")})
public class ZoneCharge implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    protected ZoneChargePK zoneChargePK;

    @Column(name = "charge", precision = 35, scale = 2)
    private BigDecimal charge;

    @JoinColumn(name = "zone_id", referencedColumnName = "zone_id", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private ZoneTable zoneTable;

    @JoinColumn(name = "weight_id", referencedColumnName = "weight_id", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private Weight weight;
@Embeddable
public class ZoneChargePK implements Serializable {
    @Basic(optional = false)
    @Column(name = "zone_id", nullable = false)
    private long zoneId;
    @Basic(optional = false)
    @Column(name = "weight_id", nullable = false)
    private long weightId;
}

ZoneChargePK
实体:

@Entity
@Table(name = "weight", catalog = "social_networking", schema = "", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"weight_id"})})
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Weight.findAll", query = "SELECT w FROM Weight w"),
    @NamedQuery(name = "Weight.findByWeightId", query = "SELECT w FROM Weight w WHERE w.weightId = :weightId"),
    @NamedQuery(name = "Weight.findByWeight", query = "SELECT w FROM Weight w WHERE w.weight = :weight")})
public class Weight implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "weight_id", nullable = false)
    private Long weightId;
    @Column(name = "weight", precision = 35, scale = 2)
    private BigDecimal weight;



    @OneToMany(cascade = CascadeType.ALL, mappedBy = "weight", fetch = FetchType.LAZY)
    private Set<ZoneCharge> zoneChargeSet;    //<-------------------------
}
@Entity
@Table(name = "zone_charge", catalog = "social_networking", schema = "")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "ZoneCharge.findAll", query = "SELECT z FROM ZoneCharge z"),
    @NamedQuery(name = "ZoneCharge.findByZoneId", query = "SELECT z FROM ZoneCharge z WHERE z.zoneChargePK.zoneId = :zoneId"),
    @NamedQuery(name = "ZoneCharge.findByWeightId", query = "SELECT z FROM ZoneCharge z WHERE z.zoneChargePK.weightId = :weightId"),
    @NamedQuery(name = "ZoneCharge.findByCharge", query = "SELECT z FROM ZoneCharge z WHERE z.charge = :charge")})
public class ZoneCharge implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    protected ZoneChargePK zoneChargePK;

    @Column(name = "charge", precision = 35, scale = 2)
    private BigDecimal charge;

    @JoinColumn(name = "zone_id", referencedColumnName = "zone_id", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private ZoneTable zoneTable;

    @JoinColumn(name = "weight_id", referencedColumnName = "weight_id", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private Weight weight;
@Embeddable
public class ZoneChargePK implements Serializable {
    @Basic(optional = false)
    @Column(name = "zone_id", nullable = false)
    private long zoneId;
    @Basic(optional = false)
    @Column(name = "weight_id", nullable = false)
    private long weightId;
}
根据这种关系,如上所示的JPQL查询工作正常


这不是一个社交网络项目。这只是最初的打算。因此它被命名为这样的。这是关于一个购物网站。

您是如何定义JPA实体之间的关系的?抱歉,编辑成一个更详细的问题。在您的选择中,您似乎使用了join.get(ZoneCharge.zoneTable),而不是join.get(ZoneCharge.charge)吗?您还需要where子句criteriaQuery.where(criteriaBuilder.equal(join.get(“zoneChargePK”).get(“zoneId”)、criteriaBuilder.parameter(java.lang.Long.class,“param”))或类似的语句。然后,查询需要使用query.setParameter(“param”,zoneIdValue)传入“param”下次请仅添加与question@Chris:您可以将其添加为答案。事实证明是正确的。我实际上需要加入
,而不是
WHERE
。我在这个问题中忽略了这一点,并发布了一个新问题,但评论回答了这个问题。
@Embeddable
public class ZoneChargePK implements Serializable {
    @Basic(optional = false)
    @Column(name = "zone_id", nullable = false)
    private long zoneId;
    @Basic(optional = false)
    @Column(name = "weight_id", nullable = false)
    private long weightId;
}