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属性里,名称就是类名小写开头,如
  1. User user = sqlManager.select("user.selectUserAndDepartment",User.class,paras); Department
  2. //dept = user.getDepartment();
  3. dept = user.get("department");

如下是个例子,假设user表与department表示一对一关系,user.departmentId对应于deparment.id,因此关系映射是{"departmentId":"id"} user与 role表示多对多关系,通过user_role做关联

  1. selectUserAndDepartment
  2. ===
  3. select * from user where user_id=#userId#
  4. @orm.single({"departmentId":"id"},"Department");
  5. @orm.many({"id":"userId"},"user.selectRole","Role");
  6. selectRole
  7. ===
  8. select r.* from user_role ur left join role r on ur.role_id=r.id
  9. where ur.user_id=#userId#

java代码的样子:

  1. User user = sqlManager.select("user.selectUserAndDepartment",User.class,paras);
  2. Department dept = user.get("department");
  3. 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支持

  1. public class TailBean implements Tail {
  2. protected Map<String,Object> extMap = new HashMap<String,Object>();
  3. boolean hasLazy = false ;
  4. public Object get(String key){
  5. if(hasLazy){
  6. Object o = extMap.get(key);
  7. if(o instanceof LazyEntity ){
  8. LazyEntity lazyEntity = (LazyEntity)o;
  9. try{
  10. Object real = lazyEntity.get();
  11. extMap.put(key, real);
  12. return real;
  13. }catch(RuntimeException ex){
  14. throw new BeetlSQLException(BeetlSQLException.ORM_LAZY_ERROR,"Lazy Load Error:"+key+","+ex.getMessage(),ex);
  15. }
  16. }else{
  17. return o;
  18. }
  19. }else{
  20. return extMap.get(key);
  21. }
  22. }
  23. public void set(String key,Object value){
  24. if(value instanceof LazyEntity ){
  25. hasLazy = true;
  26. }
  27. this.extMap.put(key, value);
  28. }
  29. }

23.2. ORM 注解

不必要为每个sql语句写映射关系或者是使用一个公共的映射关系,可以在映射的实体类上注解映射关系从而实现懒加载机制,如

  1. @OrmQuery(
  2. value={
  3. @OrmCondition(target=Department.class,attr="departmentId",targetAttr="id",type=OrmQuery.Type.ONE,lazy=false),
  4. @OrmCondition(target=ProductOrder.class,attr="id",targetAttr="userId" ,type=OrmQuery.Type.MANY),
  5. @OrmCondition(target=Role.class,attr="id",targetAttr="userId" ,sqlId="user.selectRole",type=OrmQuery.Type.MANY)
  6. }
  7. )
  8. public class User extends TailBean {
  9. private Integer id ;
  10. private String name ;
  11. private Integer departmentId;
  12. //忽略getter setter
  13. }

OrmQuery 标注在类上,OrmCondition 声明了一个懒加载关系.因此,在以后beetlsql的关于此实体的查询,都可以进一步使用懒加载查询.

如果sql语句里也申明了ORM查询,则会和注解的里ORM注解做合并,遇到映射同一个实体,则以sql语句里的映射配置为准