有些数据库不支持视图的创建,而实际业务中我们需要通过视图才能实现我们的需求,这时就可以使用Hibernate中子查询(subselect)
一,官方文档说明
There is no difference between a view and a base table for a Hibernate mapping. This is transparent at the database level, although some DBMS do not support views properly, especially with updates. Sometimes you want to use a view, but you cannot create one in the database (i.e. with a legacy schema). In this case, you can map an immutable and read-only entity to a given SQL subselect expression using @org.hibernate.annotations.Subselect
:
@Entity
@Subselect("select item.name, max(bid.amount), count(*) "
+ "from item "
+ "join bid on bid.item_id = item.id "
+ "group by item.name")
@Synchronize( {"item", "bid"} ) //tables impacted
public class Summary {
@Id
public String getId() { return id; }
...
}
定义这个实体用到的表为同步(synchronize),确保自动刷新(auto-flush)正确执行,并且依赖原实体的查询不会返回过期数据。在属性元素和嵌套映射元素中都可使用 <subselect>
。
We will now explore the same options using the hbm.xml structure. You can declare a persistent class using the class
element. For example:
<class
name="ClassName"
table="tableName"
discriminator-value="discriminator_value"
mutable="true|false"
schema="owner"
catalog="catalog"
proxy="ProxyInterface"
dynamic-update="true|false"
dynamic-insert="true|false"
select-before-update="true|false"
polymorphism="implicit|explicit"
where="arbitrary sql where condition"
persister="PersisterClass"
batch-size="N"
optimistic-lock="none|version|dirty|all"
lazy="(16)true|false"
entity(17)-name="EntityName"
check=(18)"arbitrary sql check condition"
rowid=(19)"rowid"
subsel(20)ect="SQL expression"
abstra(21)ct="true|false"
node="element-name"
/>
(1)name(可选):持久化类(或者接口)的 Java 全限定名。 如果这个属性不存在,Hibernate 将假定这是一个非 POJO 的实体映射。
(2)table(可选 — 默认是类的非全限定名):对应的数据库表名。
(3)discriminator-value(可选 — 默认和类名一样):一个用于区分不同的子类的值,在多态行为时使用。它可以接受的值包括 null 和 not null。
(4)mutable(可选,默认值为 true):表明该类的实例是可变的或者不可变的。
(5)schema(可选):覆盖在根 <hibernate-mapping> 元素中指定的 schema 名字。
(6)catalog(可选):覆盖在根 <hibernate-mapping> 元素中指定的 catalog 名字。
(7)proxy(可选):指定一个接口,在延迟装载时作为代理使用。你可以在这里使用该类自己的名字。
(8)dynamic-update(可选,默认为 false):指定用于 UPDATE 的 SQL 将会在运行时动态生成,并且只更新那些改变过的字段。
(9)dynamic-insert(可选,默认为 false):指定用于 INSERT 的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。
(10)select-before-update(可选,默认为 false):指定 Hibernate 除非确定对象真正被修改了(如果该值为 true — 译注),否则不会执行 SQL UPDATE 操作。在特定场合(实际上,它只在一个瞬时对象(transient object)关联到一个新的 session 中时执行的 update() 中生效),这说明 Hibernate 会在 UPDATE 之前执行一次额外的 SQL SELECT 操作来决定是否确实需要执行 UPDATE。
(11)polymorphisms (optional - defaults to implicit): determines whether implicit or explicit query polymorphisms is used.
(12)where(可选)指定一个附加的 SQL WHERE 条件,在抓取这个类的对象时会一直增加这个条件。
(13)persister(可选):指定一个定制的 ClassPersister。
(14)batch-size(可选,默认是 1)指定一个用于 根据标识符(identifier)抓取实例时使用的 "batch size"(批次抓取数量)。
(15)optimistic-lock(乐观锁定)(可选,默认是 version):决定乐观锁定的策略。
(16)lazy(可选):通过设置 lazy="false",所有的延迟加载(Lazy fetching)功能将被全部禁用(disabled)。
(17)entity-name (optional - defaults to the class name): Hibernate3 allows a class to be mapped multiple times, potentially to different tables. It also allows entity mappings that are represented by Maps or XML at the Java level. In these cases, you should provide an explicit arbitrary name for the entity. See 第 4.4 节 “动态模型(Dynamic models)” and 第 20 章 XML 映射 for more information.
(18)check(可选):这是一个 SQL 表达式, 用于为自动生成的 schema 添加多行(multi-row)约束检查。
(19)rowid(可选):Hibernate 可以使用数据库支持的所谓的 ROWIDs,例如:Oracle 数据库,如果你设置这个可选的 rowid,Hibernate 可以使用额外的字段 rowid 实现快速更新。ROWID 是这个功能实现的重点,它代表了一个存储元组(tuple)的物理位置。
(20)subselect(可选):它将一个不可变(immutable)并且只读的实体映射到一个数据库的子查询中。当你想用视图代替一张基本表的时候,这是有用的,但最好不要这样做。更多的介绍请看下面内容。
(21)abstract(可选):用于在 <union-subclass> 的层次结构(hierarchies)中标识抽象超类。
若指明的持久化类实际上是一个接口,这也是完全可以接受的。之后你可以用元素 <subclass>
来指定该接口的实际实现类。你可以持久化任何 static(静态的)内部类。你应该使用标准的类名格式来指定类名,比如:Foo$Bar
。
Here is how to do a virtual view (subselect) in XML:
<class name="Summary">
<subselect>
select item.name, max(bid.amount), count(*)
from item
join bid on bid.item_id = item.id
group by item.name
</subselect>
<synchronize table="item"/>
<synchronize table="bid"/>
<id name="name"/>
...
</class>
The <subselect>
is available both as an attribute and a nested mapping element.
二,个人对hibernate子查询的理解举例
1,基于视图的查询举例
a)创建实体类(介于文章的长度,get和set方法的代码就不贴出来了)
@Entity
@Table(name="T_Order")
public class Order {
@Id
@GeneratedValue
private int id;
private String name;
@Entity
public class OrderItem {
@Id
@GeneratedValue
private int id;
private String name;
private Double price;
private int count;
@ManyToOne
private Order order;
b)创建子查询视图(视图的字段是子查询的子集,即视图的字段要在子查询中可以找到对应的列)
@Entity
@Subselect("select o.id, o.name,sum(oi.price * oi.count) as count "
+ "from T_Order o , OrderItem oi WHERE o.id = oi.order_id "
+ "group by o.id , o.name ")
@Synchronize({ "T_Order", "OrderItem" })
public class OrderView {
@Id
private int id;
private String name;
private double count;
c)创建测试类
public class OrderTest {
static SessionFactory factory = null;
@BeforeClass
public static void beforeClass(){
factory = new AnnotationConfiguration().configure().buildSessionFactory();
}
@Test
public void testGet(){
Session session = factory.getCurrentSession();
session.beginTransaction();
Order o = new Order();
o.setName("order1");
session.save(o);
for(int i = 0 ; i< 5 ; i++){
OrderItem oi = new OrderItem();
oi.setName("oi"+i);
oi.setPrice(2.0);
oi.setCount(4);
oi.setOrder(o);
session.save(oi);
}
session.getTransaction().commit();
Session session2 = factory.getCurrentSession();
session2.beginTransaction();
List<OrderView> list = session2.createQuery("From OrderView ").list();
for(OrderView ov : list){
System.out.println(ov.getId());
System.out.println(ov.getName());
System.out.println(ov.getCount());
}
session2.getTransaction().commit();
}
}
d)测试类输出结果
1
order1
40.0