【问题标题】:JPQL - JOIN query with filterJPQL - 使用过滤器连接查询
【发布时间】:2019-07-22 02:49:37
【问题描述】:

我有实体:

第一

@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);
    }

第二:

@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;
}

我想从我的数据库中获取结果,其中包含每个对象技术中的列表我有列表 technicStatusList = new ArrayList(),我希望在其中只有值为 isActive=true 的 TechnicStatus。

为此,我对相同的 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);

但是得到一个包含 TechnicStatus 的结果,它返回一个带有真假的 TechnicStatus (TechnicStatus.isActive=true, TechnicStatus.isActive=false)。

我想得到这个原生查询的结果:

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

【问题讨论】:

  • 对于您的 JPA 查询,您需要执行 SELECT t, ts FROM ... 广告从结果中提取 tts。请注意,当您仅加载 Technic 时,这些实体的 technicStatusList 将包含 all 关联的状态实体 - 由于技术原因(例如 Hibernate 不知道该列表中的元素是否会表示全部或只是一个过滤的子集 - 这会在尝试将该列表的更改写回数据库时导致问题)。

标签: java mysql hibernate jpa jpql


【解决方案1】:

与技术关联的 TechnicalStatus 列表将始终是您的映射定义的完整列表。

基本上你有两个选择。如果您只曾经对处于 Active 状态的 TechnicalStatus 感兴趣,那么您可以在关联上使用非便携式、Hibernate 特定的 @Where 子句。

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

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

否则你所做的只是从查询方法返回一个技术状态列表,这不是你想要的,而是你所拥有的。

【讨论】:

    【解决方案2】:

    无法在查询条件中过滤相关集合。您可以通过在 TechnicalStatus 上进行选择来获得它:select ts from TechnicStatus ts join Technic t where ...

    我注意到的其他事情:

    添加新状态时,您正在覆盖现有状态列表:

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

    在字段声明中初始化technicStatusList。技术中的添加方法:

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

    我注意到的其他事情:

    使用连接时不要使用on t.id = ts.technic.id。 JPA 将在您编写时创建正确的本机 SQL:join TechnicStatus ts WHERE ...

    【讨论】:

      猜你喜欢
      • 2019-01-26
      • 2018-02-21
      • 2014-02-21
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 2020-11-04
      • 2020-10-05
      • 2018-07-06
      相关资源
      最近更新 更多