简体   繁体   English

JPQL - 使用过滤器连接查询

[英]JPQL - JOIN query with filter

I have the entitys:我有实体:

First第一的

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Technic implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String gosNumber;

    private String invNumber;

    private String shassisNumber;

    private String engineNumber;

    @Column(length = 100)
    private String yearOfMake;

    @ManyToOne
    private Farm farm;

    @JsonManagedReference
    @ManyToOne
    private TechGroup techGroup;

    @JsonManagedReference
    @ManyToOne
    private TechType techType;

    @JsonManagedReference
    @ManyToOne
    private TechMark techMark;

    @JsonIgnore
    @CreationTimestamp
    @Column(name = "creation_date", updatable = false)
    private LocalDateTime createdDate;

    @JsonIgnore
    @Column(name = "updated_date")
    @UpdateTimestamp
    private LocalDateTime updatedDate;

    @JsonIgnore
    @Column(columnDefinition = "Bool default false")
    private Boolean isDel;


    @JsonManagedReference
    @OneToMany(mappedBy = "technic")
    private List<TechnicStatus> technicStatusList = new ArrayList<>();

    public List<TechnicStatus> getTechnicStatusList() {
        return technicStatusList;
    }

    public void setTechnicStatus(TechnicStatus technicStatus) {
        this.technicStatusList = new ArrayList<>();
        this.technicStatusList.add(technicStatus);
    }

Second:第二:

@Entity
@Getter
@Setter
@NoArgsConstructor
public class TechnicStatus implements Serializable  {



    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "technic_status_id")
    private Long id;

    @JsonBackReference
    @ManyToOne
    private Technic technic;

    @JsonManagedReference
    @ManyToOne
    private Status status;

    private Boolean isGarantia;

    private Boolean isLizing;

    private LocalDate visitedDate;

    private LocalDate notWorkDate;

    private String description;

    @JsonIgnore
    private boolean isActive;

    @JsonIgnore
    @CreationTimestamp
    @Column(name = "creation_date", updatable = false)
    private LocalDateTime createdDate;
}

I want to get result from my db which contains the List in each object Technic i have List technicStatusList = new ArrayList<>() in which i want to have a TechnicStatus only with value is isActive=true.我想从我的数据库中获取结果,其中包含每个对象技术中的列表我有列表 technicStatusList = new ArrayList<>(),我希望在其中只有一个值为 isActive=true 的 TechnicStatus。

For this i right same JPQL query:为此,我正确的 JPQL 查询:

TypedQuery<Technic> query = em.createQuery("Select t  from Technic t join TechnicStatus ts on t.id = ts.technic.id where t.isDel=false and ts.isActive=true and t.farm.id=:farmId order by t.techGroup.name, t.techType.name, t.techMark.name", Technic.class);

But get a result containing TechnicStatus, which returns a TechnicStatus with true and false (TechnicStatus.isActive=true, TechnicStatus.isActive=false).但是得到一个包含 TechnicStatus 的结果,它返回一个带有真假的 TechnicStatus (TechnicStatus.isActive=true, TechnicStatus.isActive=false)。

I want to get result as this native query:我想得到这个本机查询的结果:

SELECT 
    *
FROM
    technic
        JOIN
    technic_status ON technic.id = technic_status.technic_id
WHERE
    technic.is_del = FALSE
        AND technic_status.is_active = TRUE
        AND technic.farm_id = 1722

The List of TechnicalStatus associated with a Technic will always be the complete list as defined by your mappings.与技术关联的技术状态列表将始终是您的映射定义的完整列表。

Essentially then you have 2 options.基本上你有2个选择。 If you are only ever interested in TechnicalStatus with a status of Active then you can use the non-portable, Hibernate specific @Where clause on the association.如果您只对状态为 Active 的 TechnicalStatus 感兴趣,那么您可以在关联上使用不可移植的、Hibernate 特定的@Where子句。

@JsonManagedReference
@OneToMany(mappedBy = "technic")
@Where("active = 1")
private List<TechnicStatus> technicStatusList = new ArrayList<>();

https://dzone.com/articles/hibernate-where-clause https://dzone.com/articles/hibernate-where-clause

Otherwise all you do is return a List of TechnicalStatus from query method which is not what you want but is all you have.否则,您所做的只是从查询方法返回一个技术状态列表,这不是您想要的,而是您所拥有的。

Its not possible to filter related collection in query conditions.无法在查询条件中过滤相关集合。 You can get it by doing select on TechnicalStatus: select ts from TechnicStatus ts join Technic t where ...您可以通过在 TechnicalStatus 上进行选择来获得它: select ts from TechnicStatus ts join Technic t where ...

Other thing I noticed:我注意到的另一件事:

You are overwriting list of existing statuses when adding new one:添加新状态时,您正在覆盖现有状态列表:

public void setTechnicStatus(TechnicStatus technicStatus) {
     this.technicStatusList = new ArrayList<>();
     this.technicStatusList.add(technicStatus);
}

Initialize technicStatusList in field declaration.在字段声明中初始化technicStatusList Method in Technic for adding:技术中的添加方法:

public void addTechnicStatus(TechnicStatus technicStatus) {
    getTechnicStatusList().add(technicStatus);
    technicStatus.setTechnic(this);
}

Other thing I noticed:我注意到的另一件事:

When using join don't use on t.id = ts.technic.id .使用 join 时不要on t.id = ts.technic.id使用。 JPA will create correct native SQL just when you write: join TechnicStatus ts WHERE ... JPA 将在您编写时创建正确的本机 SQL: join TechnicStatus ts WHERE ...

Using join fetch should solve the issue, this would force the query to run eagerly all at once and only bring back the records that match the where clause.使用 join fetch 应该可以解决这个问题,这将迫使查询一次急切地运行,并且只带回与 where 子句匹配的记录。 so your query would be:所以你的查询是:

TypedQuery<Technic> query = em.createQuery("Select t from Technic t join fetch TechnicStatus ts where t.isDel=false and ts.isActive=true and t.farm.id=:farmId order by t.techGroup.name, t.techType.name, t.techMark.name", Technic.class);

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

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