2016-04-08 37 views
1

我有一个SQL查询,可以准确获取我需要的数据。问题是我们试图在JPA Criteria API中表达所有查询以保持可移植性,并且我无法弄清楚如何映射这个特定的查询。SQL查询过于复杂以便在JPA Criteria API中显示?

问题是JPA Criteria API子查询类缺少CriteriaQuery类所具有的multiselect()方法。正如你在SQL查询中看到的那样,我计算了子查询中实体中不存在的字段。因此,我无法检索这些字段。

如果有人知道解决方案或可以提供指导,或者即使有人可以验证我在JPA Criteria API中实现的功能是不可能的,我也会非常感激。

的SQL:

SELECT w.NAME AS 'wave_name', 
    Count(*) AS 'num_lines', 
    Sum(qty_ordered) AS 'num_units', 
    Count(DISTINCT unit_of_work_id) AS 'num_units_of_work', 
    Sum(completed_units) AS 'completed_units', 
    (Sum(completed_units) + Sum(qty_scratched))/Sum(qty_ordered) AS 'perc_completed_units' 
FROM (SELECT t.id, 
      t.wave_id, 
      t.quantity_requested AS 'qty_ordered', 
      t.quantity_scratched AS 'qty_scratched', 
      t.unit_of_work_id  AS 'unit_of_work_id', 
      Ifnull(m.quantity, 0) AS 'qty_picked', 
      CASE 
      WHEN Ifnull(m.quantity, 0) > quantity_requested THEN 
      quantity_requested 
      ELSE Ifnull(m.quantity, 0) 
      END     AS 'completed_units' 
    FROM task t 
      LEFT OUTER JOIN (SELECT move.task_id, 
            Sum(quantity) AS 'quantity' 
          FROM move 
          GROUP BY task_id) m 
         ON m.task_id = t.id) s 
    JOIN wave w 
    ON w.id = s.wave_id 
GROUP BY w.name; 

的实体:

@Entity 
@Table(name = "task") 
public class Task { 

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

    @ManyToOne (cascade = CascadeType.ALL) 
    @JoinColumn (name = "wave_id", nullable = false) 
    private Wave wave; 

    @ManyToOne (cascade = CascadeType.ALL) 
    @JoinColumn (name = "unit_of_work_id", nullable = false) 
    private UnitOfWork unitOfWork; 

    @OneToMany (cascade = CascadeType.ALL, mappedBy = "task") 
    private Set<Move> moves = new HashSet<Move>(); 

    @Column (name = "quantity_requested") 
    private Long quantityRequested; 

    @Column (name = "quantity_scratched") 
    private Long quantityScratched; 
} 

@Entity 
@Table(name = "wave") 
public class Wave { 

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

    @Column(name = "name") 
    private String name; 

    @OneToMany(mappedBy = "wave", cascade = CascadeType.ALL) 
    private Set<Task> tasks = new HashSet<Task>(); 
} 

@Entity 
@Table(name = "unit_of_work") 
public class UnitOfWork { 

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

    @OneToMany(mappedBy = "unitOfWork", cascade = CascadeType.ALL) 
    private Set<Task> tasks = new HashSet<Task>(); 
} 

@Entity 
@Table(name = "move") 
public class Move { 

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

    @ManyToOne (cascade = CascadeType.ALL) 
    @JoinColumn (name = "task_id", nullable = false) 
    private Task task; 

    @Column (name = "quantity") 
    private Long quantity; 
} 
+0

为什么只有条件查询为什么不使用命名参数或原生查询方式?如果查询很大,则使用标准方法是没有意义的。 – Arun

+0

我正在处理的项目有一个基于标准的模块,它有助于一般性地将过滤器应用于支持系统中特定数据网格的“预先准备好的”条件查询。直到这一点,“罐装”查询相对简单,这种方法已经足够。但随着更复杂的需求呈现出来,我一直在努力使其对于所有查询都足够通用。我认为,在我的例子中,像这样的疑问就是对这种方法的有力证据。 – Jon

+0

我已经提供了一个示例作为条件的替代方法,请检查它。在这种情况下,我认为标准不是一个好方法。 – Arun

回答

0

我要说的命名参数或本地查询方法这一点。

例如:

命名参数:

public interface Repo extends JpaRepository<AEntity, String> { 
    @Query("select a from AEntity a where a.BEntity.name = :name") 

    public aMethod(@Param("name") String name) 
    } 

OR

本地查询方法:

public interface Repo extends JpaRepository<AEntity, String> {  
    @Query(value = "select * from Tablename t where t.name = :name", nativeQuery=true) 

    public aMethod(@Param("name") String name) 
    } 

检查这个链接,如果您使用的春天JPA

http://docs.spring.io/spring-data/data-jpa/docs/1.4.x/reference/htmlsingle/#jpa.named-parameters