2014-04-29 160 views
0

我们,如果我们创建下面的视图JPA如何处理视图?

CREATE VIEW V_ABC AS 
SELECT TABLE_A.id as id, SUM(TABLE_A.a+TABLE_B.b-TABLE_C.c) as total, TABLE_A.a as a,TABLE_B.b as b,TABLE_C.c as c 
FROM TABLE_A 
join TABLE_B on TABLE_A.id = TABLE_B.fid 
join TABLE_C on TABLE_B.id = TABLE_C.fid 
GROUP BY TABLE_A.a,TABLE_B.b,TABLE_C.c; 

的发言权和实体映射到这个观点

public class VABC{ 
    private Long id; 
    private BigDecimal total; 
    private BigDecimal a; 
    private BigDecimal b; 
    private BigDecimal c; 

}

我的问题是,在J2EE应用程序中,每次当调用任何字段来自VABC的实例,如下所示:

VABC vabc = VABC.findById(id); 
BigDecimal currentTotal = vabc.getTotal(); 

JPA是否必须对视图执行整个上述查询,然后获取当前结果?

回答

2

JPA不知道这是一个观点,因为它是透明的,也就是说,它会尽量选择是这样的:

SELECT f1,... FROM V_ABC where id=? 

和数据库会翻译这相应JOIN & SUM()操作。

PS:为了检查,您可以启用所有SQL查询的日志记录并查看发送到数据库的内容。

+0

谢谢。也只是双重证实,它实际上是视图'V_ABC'的数据库查询,它是否只是JPQL实现'getter'方法从视图查询结果中检索'SELECT total FROM V_ABC ...'? – Dreamer

+1

是的(你制定它有点模糊)。 DB实际上会执行您在定义视图时编写的视图查询/逻辑。 JPA只会获取某种Map fieldName => fieldValue,并将该值设置为相应的Java属性(例如通过调用setter'setTotal()') –

1

如果您想轻松将您的视图(结果集)映射到实体类中,您可以利用所谓的构造函数表达式,这是JPQL或Criteria API功能之一。

假设你已经定义要么JPQL或标准API查询,例如:

JPQL

SELECT NEW com.dreamer.jpa.VABC(ta.id, SUM(ta.a + tb.b - tc.c), ta.a, tb.b, tc.c) 
FROM TableA ta JOIN ta.b tb JOIN tb.c tc 
WHERE ta.id = tb.fid AND tb.id = tc.fid 
GROUP BY ta.a, tb.b, tc.c 

标准API

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<TableA> cq = cb.createQuery(TableA.class); 
Root<TableA> ta = c.from(TableA.class); 
Join<TableA, TableB> tb = ta.join("b"); 
Join<TableB, TableC> tc = tb.join("c"); 
cq.where(cb.and(
       cb.equal(ta.get("id"), tb.get("fid")), 
       cb.equal(tb.get("id"), tc.get("fid")) 
       ) 
     ); 
cq.groupBy(ta.get("a"), tb.get("b"), tc.get("c")); 
cb.select(cb.construct(com.dreamer.jpa.VABC.class, 
         ta.get("id"), 
         cb.diff(cb.sum(ta.get("a"), tb.get("b")), tc.get("c")), 
         ta.get("a"), 
         tb.get("b"), 
         tc.get("c") 
        ) 
     ); 

这些查询的结果类型的com.dreamer.jpa.VABC类,可以定义如下:

package com.dreamer.jpa; //must conform the fully qualified name in the queries 

public class VABC { 
    private int id; 
    private BigDecimal total; 
    private BigDecimal a; 
    private BigDecimal b; 
    private BigDecimal c; 

    public VABC(int id,BigDecimal total,BigDecimal a,BigDecimal b,BigDecimal c) { 
     this.id = id; 
     // ... 
    } 
} 

现在,在执行查询持久性提供(查询处理器)遍历所述查询的结果,并且每个表行被返回,com.dreamer.jpa.VABC类的新实例使用相匹配的表达类型的构造实例化在查询中列出。

该方法有助于构建用于其他应用层的粗粒度DTO/VO的过程。代替从结果列表中手动构建这样的对象,可以使用单个查询来检索对象的完整列表,即已经准备好推入表示层。


另一种选择是创建一个直接映射到现有数据库视图的实体。因此,你可以选择直接从映射视图:

JPQL

SELECT v FROM VABC v 

标准API

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<VABC> cq = cb.createQuery(VABC.class); 
Root<VABC> ta = cq.from(VABC.class); 

是指数据库视图的实体类可以被定义如下:

@Entity 
@Table(name = "V_ABC") 
public class VABC { 
    private Long id; 
    private BigDecimal total; 
    private BigDecimal a; 
    private BigDecimal b; 
    private BigDecimal c; 

    public VABC(int id,BigDecimal total,BigDecimal a,BigDecimal b,BigDecimal c) { 
     this.id = id; 
     // ... 
    } 
} 

将数据库视图直接映射到实体中会产生比构造函数表达式方法更简洁的代码。在这种情况下,基于JPQL/Criteria的查询在查询数据库时产生一个简单的SELECT id, total, a, b, c FROM V_ABC

该方法还有助于构建用于其他应用程序层的粗粒度DTO/VO的过程。一个查询返回代表V_ABC视图行的VABC实体实例的完整列表。

+0

谢谢!那么我可以说在这种情况下基本上没有必要在数据库中创建视图?我认为,考虑到性能问题,最好将工作负载留给Oracle而不是JPA(因为JPA必须添加额外的进程层来将JPQL/Criteria Query转换为SQL,并且我感觉并不是所有JPA的实现都做得很好,当有很多连接时,将JPQL转换为高效的SQL) – Dreamer

+1

我不会那么说。您可能需要为各种目的创建视图。像往常一样 - 这只是性能,便携性,便利性等方面的选择问题。我想你专注于性能,因此我宁愿尝试将视图映射到实体,然后使用本机SQL查询进行数据检索。我已经更新了一些答案,使其更加完整。 – wypieprz