23. ORM
注意
- BeetlSql的Pojo类与数据库表对应,如果Pojo有对应的属性,可以直接映射到属性上,这个同其他ORM工具一样,如果没有关系映射相关特性,实现@Tail 或者继承TailBean(或者实现Tail接口),额外的关系映射才会放到tail属性里供查询的时候调用。
- 要注意的是,beetlsql的orm 仅仅限于查询结果集,而不包括新增,更新,删除。这些需要调用sqlManager的api直接操作就行了而不像JPA那样还需要成为容器管理对象才能更新
- 无论是sql语句里配置orm查询,还是通过注解来配置orm查询,都不强求数据库一定有此映射关系,只要当运行调用的时候才会触发orm查询.对于eager查询,当调用beetlsql的时候,会触发ORM查询,对于lazy查询,并不会触发,只会在获取关系属性的时候的,再触发.
23.1. sql语句里的ORM查询
beetlsql 关系映射是在sql语句里通过orm.single和 orm.many,orm.lazySingle,orm.lazyMany 函数进行申明。beetlsql会根据这些申明来完成关系映射
orm.single,orm.many ,orm.lazySingle,orm.lazyMany函数名字本身说明了是一对一,还是一对多或者多对多。以及是直接加载还是懒加载。函数可以放在sql语句任何地方,建议放到头部或者尾部,参数格式有俩种形式,
- 使用模板方式查询关系对象,orm.single({"departmentId","id"},"Department") 第一个参数申明了关系映射,即sql查询结果里属性(非字段名),对应到关系表的查询属性, 如User对象里,departmentId应到Department对象的id,beetlsql会根据此关系发起一次template查询。映射的结果集放在第二个参数Department类里,如果Department与User类在同一个包下,可以省略包名,否则需要加上类包名
- 使用sqlId来查询关系对象,orm.single({"departmentId","id"},"user.selectDepatment","Department") 第一个参数还是映射关系,第二个参数是一sql查询id,beetlsql将查询此sql语句,将结果集放到第三个参数Deparmtent类里
- lazy 意味着当调用的时候再加载。如果在事务外调用,并不会像hibernate,JPA那样报错,beetlsql会再用一个数据库连接去查询。一般来讲,如果业务代码确定要用,建议不用lazy方式。因为lazy不会有查询优化,性能可能慢一些.需要注意的是,Beetlsql并非通过proxy技术来实现lazy加载,因此对于lazy加载,你需要继承TailBean
- 映射关系可以用别名,如User对象有myDepartment属性,则映射可以写成orm.single({"departmentId","id"},"Department",{"alias":"myDepartment"}) 如上查询关系对象,结果放到对应的属性上(lazy加载不能放到属性上),或者放到tail属性里,名称就是类名小写开头,如
User user = sqlManager.select("user.selectUserAndDepartment",User.class,paras); Department
//dept = user.getDepartment();
dept = user.get("department");
如下是个例子,假设user表与department表示一对一关系,user.departmentId对应于deparment.id,因此关系映射是{"departmentId":"id"} user与 role表示多对多关系,通过user_role做关联
selectUserAndDepartment
===
select * from user where user_id=#userId#
@orm.single({"departmentId":"id"},"Department");
@orm.many({"id":"userId"},"user.selectRole","Role");
selectRole
===
select r.* from user_role ur left join role r on ur.role_id=r.id
where ur.user_id=#userId#
java代码的样子:
User user = sqlManager.select("user.selectUserAndDepartment",User.class,paras);
Department dept = user.get("department");
List<Role> roles = user.get("role");
完整的orm查询例子可以参考 https://code.csdn.net/xiandafu/beetlsql_orm_sample/tree/master 还有文档
http://my.oschina.net/xiandafu/blog/735809
注意
lazy方式只能继承TailBean才行,如果实现Tail接口,或者@Tail,你取出来的对象并不是你期望的Pojo,而是LazyEntity,你还需要调用get()方法获取到期数据库查询结果 ,可以参看TailBean代码来实现你的Lazy支持
public class TailBean implements Tail {
protected Map<String,Object> extMap = new HashMap<String,Object>();
boolean hasLazy = false ;
public Object get(String key){
if(hasLazy){
Object o = extMap.get(key);
if(o instanceof LazyEntity ){
LazyEntity lazyEntity = (LazyEntity)o;
try{
Object real = lazyEntity.get();
extMap.put(key, real);
return real;
}catch(RuntimeException ex){
throw new BeetlSQLException(BeetlSQLException.ORM_LAZY_ERROR,"Lazy Load Error:"+key+","+ex.getMessage(),ex);
}
}else{
return o;
}
}else{
return extMap.get(key);
}
}
public void set(String key,Object value){
if(value instanceof LazyEntity ){
hasLazy = true;
}
this.extMap.put(key, value);
}
}
23.2. ORM 注解
不必要为每个sql语句写映射关系或者是使用一个公共的映射关系,可以在映射的实体类上注解映射关系从而实现懒加载机制,如
@OrmQuery(
value={
@OrmCondition(target=Department.class,attr="departmentId",targetAttr="id",type=OrmQuery.Type.ONE,lazy=false),
@OrmCondition(target=ProductOrder.class,attr="id",targetAttr="userId" ,type=OrmQuery.Type.MANY),
@OrmCondition(target=Role.class,attr="id",targetAttr="userId" ,sqlId="user.selectRole",type=OrmQuery.Type.MANY)
}
)
public class User extends TailBean {
private Integer id ;
private String name ;
private Integer departmentId;
//忽略getter setter
}
OrmQuery 标注在类上,OrmCondition 声明了一个懒加载关系.因此,在以后beetlsql的关于此实体的查询,都可以进一步使用懒加载查询.
如果sql语句里也申明了ORM查询,则会和注解的里ORM注解做合并,遇到映射同一个实体,则以sql语句里的映射配置为准