Mybatis 一对一、一对多、多对多关联之级联添加
示例项目:MIPO_CRM
一、一对一关联
示例:订单与销售机会
描述:在业务员与客户的联系人的联系记录中可以生成一条销售机会,而此条销售机会可生成一条订单,两者呈一对一关联。
1.表设计
opportunity(销售机会表)
orders(订单表)
2.pojo
Opportunity
/**
* 销售机会机会
* @author Administrator
*
*/
public class Opportunity implements Serializable{
private int opid;
private Float allprice;//所有商品的购买总价
private int allcount;//所有商品的购买数量
private String odate;//下单时间 private User user;//业务员
private Linkman linkman;//联系人 }
Orders
/**
* 订单
* @author Administrator
*
*/
public class Orders implements Serializable {
private String oid;//订单id private Opportunity opportunity;//销售机会 (订单与销售机会呈一对一关联)
//... }
3.下面看一下添加订单的代码是如何级联添加销售机会的:
@RequestMapping(value = "addOrder", method = RequestMethod.POST)
public String addOrder(Map<String, Object> maps, Orders orders) { // 通过opid获取销售机会
Opportunity opportunity = opportunityService.findOppById(orders
.getOpportunity().getOpid());
// ... // 生成订单oid
String oid = "";
for (int i = 0; i < 5; i++) {
oid += (int) (Math.random() * 10);
}
oid += System.currentTimeMillis() + "";// 创建订单
Orders ord = new Orders(oid, opportunity, opportunity.getLinkman(),
opportunity.getUser(), orders.getBdate(), orders.getFdate(),
opportunity.getAllprice(), 1, 1, orders.getRemark());
//... // 级联添加订单表、订单商品表
ordersService.addOrder(ord, ordergoods); return "redirect:/toPage/listOrdersPage";
}
从上面代码可看出,在添加订单时先获取销售机会,然后在创建订单时将销售机会加进去就好了。
4.最后看一下Mybatis添加订单时的SQL
添加订单(orders.xml)
<!-- 添加订单表 -->
<insert id="insert" parameterType="Orders">
insert into Orders(oid,opid,bdate,lid,uid,fdate,ysprice,flag,statues,remark)
values(#{oid},#{opportunity.opid},#{bdate},#{linkman.lid},#{user.uid},#{fdate},#{ysprice},#{flag},#{statues},#{remark})
</insert>
从上面的代码可以看出,往数据库添加订单时再把销售机会的opid(opportunity.opid)拿出来添加到订单表就可以了。
下面是数据库的数据:
说明:1.这里的一对一比较特殊一点,因为一般情况下,一对一都有一个主对象和一个附属对象,附属对象的创建依赖于主对象的创建,附属对象的主键id也是外键,它与主对象的主键id相等,因此两个对象所映射的表中不需要再创建一个列来进行关联(如账户与员工);但在这里由于订单表的主键oid不是“1,2,3..”这样的数字,在添加时无法将销售机会的主键值作为自己的主键值,因此在键表时设立一列opid来与销售机会表进行关联。2.由于添加销售机会与添加订单在业务逻辑上呈明显的先后顺序,因此没有在添加销售机会时级联添加订单或在添加订单时级联添加销售机会。
二、一对多关联
示例:订单与订单商品
描述:订单描述了客户购买商品的时间,合同截止时间,购买商品的总价、业务员、购买商品的联系人等信息,但无法描述客户具体买了哪些商品,每件商品又买了多少,购买单价是多少,该商品的利润又是多少,所以此项目创建了订单商品表以描述这些信息。因为客户在签约时生产一张订单,而该客户可能购买多件商品,所以此订单有可能对应多个订单商品,订单与订单商品呈一对多关联。
1.表设计
orders(订单表)
ordergood(订单商品表)
从订单商品表可以看出此表同过gid、oid列关联了商品表、订单表。
2.POJO
Orders
/**
* 订单
* @author Administrator
*
*/
public class Orders implements Serializable {
private String oid;//订单id private Opportunity opportunity;//销售机会 (订单与销售机会呈一对一关联)
private Linkman linkman;//联系人 (订单与联系人呈多对一关联)
private User user;//业务员 (订单与业务员呈多对一关联) private Date bdate; //开单日期
private Date fdate;//合同到期时间
private Float ysprice;//应收金额
private int statues;//审核状态
private Integer flag;//订单状态
private String remark;//备注
private Integer uids;//订单审核人 }
Ordergood
/**
* 订单商品
* @author Administrator
*
*/
public class Ordergood implements Serializable {
private Orders orders;//订单 (订单商品与订单呈多对一关联)
private Goods goods;//商品 (订单商品与商品呈多对一关联)
private Integer count;//同件商品的数量
private Float price;//同件商品的购买单价
private Float allprice;//同件商品的购买总价
private Float profit;//同件商品的单件利润 }
3.下面看一下在添加订单时是如何级联添加订单商品的:
@RequestMapping(value = "addOrder", method = RequestMethod.POST)
public String addOrder(Map<String, Object> maps, Orders orders) { // 1.通过opid查询销售机会表对应的内容
Opportunity opportunity = opportunityService.findOppById(orders
.getOpportunity().getOpid());
// 2,通过opid查询商品机会表的内容
List<Goodopp> goodopps = goodoppService.listGoodopp1(orders
.getOpportunity().getOpid()); // 生成订单oid
String oid = "";
for (int i = 0; i < 5; i++) {
oid += (int) (Math.random() * 10);
}
oid += System.currentTimeMillis() + "";
System.out.println(oid+"oid"); /**
* 获取订单的信息
* 1.生成的“订单”中的联系人、业务员、所有商品的总价从对应的“销售机会表”中获取。
* 2.生成的订单的初始状态:“审核状态”为1,表示待审核;“订单状态”为1,表示可取消订单;
* 审核人为空,表示待审核人审核。
*/
Orders ord = new Orders(oid, opportunity, opportunity.getLinkman(),
opportunity.getUser(), orders.getBdate(), orders.getFdate(),
opportunity.getAllprice(), 1, 1, orders.getRemark());
/**
* 获取订单商品的信息
* 生成的“订单商品”中的同件商品的购买价格、购买数量、商品信息从对应的“商品销售机会表”中获取。
*/
List<Ordergood> ordergoods = new ArrayList<Ordergood>();
for (Goodopp goodopp : goodopps) { Ordergood ordergood = new Ordergood();
ordergood.setOrders(ord);//设置订单
ordergood.setGoods(goodopp.getGoods());//设置商品
ordergood.setPrice(goodopp.getPrice());//设置同件商品的购买价格
ordergood.setCount(goodopp.getCount());//设置同件商品的购买数量
ordergood.setAllprice(goodopp.getPrice() * goodopp.getCount());//设置同件商品的购买总价 Goods goods = goodsService.findGoodsById(goodopp.getGoods()
.getGid());// 获取商品销售机会对应的商品
Float outprice = goodopp.getPrice();//获取同件商品的购买单价
Float inprice = goods.getCostprice();//获取同件商品的成本价
ordergood.setProfit(outprice - inprice);//设置同件商品的单件利润 ordergoods.add(ordergood);
} // 级联添加订单表、订单商品表
ordersService.addOrder(ord, ordergoods); return "redirect:/toPage/listOrdersPage";
}
4.下面是上面代码中ordersService.addOrder(ord, ordergoods);所调用服务层的代码:
/**
* 生成订单,并添加订单商品表
* @param orders
* @param ordergoods
*/
public void addOrder(Orders orders,List<Ordergood> ordergoods){
ordersDao.addOrder(orders);//添加订单
ordergoodDao.addOrdergood(ordergoods);//添加订单商品表
}
5.现在省略这两个方法所调用的模型层的方法,看下各自在Mybatis映射文件中的sql
a.添加订单的sql(orders.xml)
<!-- 添加订单表 -->
<insert id="insert" parameterType="Orders">
insert into Orders(oid,opid,bdate,lid,uid,fdate,ysprice,flag,statues,remark)
values(#{oid},#{opportunity.opid},#{bdate},#{linkman.lid},#{user.uid},#{fdate},#{ysprice},#{flag},#{statues},#{remark})
</insert>
b.添加订单商品的sql(ordergood.xml)
<!--添加订单商品表。因为一次添加的订单商品可能有多条数据,因此这里进行批量添加。-->
<insert id="addOrdergood" parameterType="java.util.List"><!-- parameterType="java.util.List"可以省略,Mybatis会自动判断参数类型。 -->
insert into ordergood(oid,gid,count,price,allprice,profit) values
<foreach collection="list" item="og" separator=","><!-- separator="," 不可以省略;item="og"是集合中每一个元素进行迭代时的别名,可以随便取。 -->
(#{og.orders.oid},#{og.goods.gid},#{og.count},#{og.price},#{og.allprice},#{og.profit})
</foreach>
</insert>
小结:Mybatis作为模型框架与Hibernate在级联添加一对多这样的关系对象的区别:
1.在定义POJO上:
从POJO的定义就可以看出,使用Mybatis作为模型层与Hibernate在定义POJO时的区别:如果是Hibernate则需要在Orders类中定义一个装Ordergood的集合,如:
private Set<Ordergood> = new HashSet<Ordergood>();
而Mybayis则只是在多的一方的POJO类中(如Ordergood)定义一的一方(Orders)就可以了。
2.在映射文件上:
Hibernate需要在映射文件中定义对象之间的关系;而Mybatis不需要。
3.在添加方式上:
Hibernate只需调用Set方法将关联的一方实例进行赋值,然后Hibernate在添加本对象至数据库时会自动地级联添加其关联对象;而Mybatis则需要手工添加本对象及关联对象。
三、多对多关联
示例:角色与权限
描述:一个角色可对应多个权限,一个权限也可对应多个角色,因此两种之间呈多对多关联。
1.表设计
role(角色表)
function(权限表)
rolefun(角色权限表)
2.POJO
Role
/**
* 角色
* @author Administrator
*
*/
public class Role implements Serializable {
private Integer rid;
private String rname;
private String rdesc; }
Function
/**
* 权限
* @author Administrator
*
*/
public class Function implements Serializable {
private Integer fid;
private String fname;
private String method;
private String submitway;//提交方式
private Integer parentid; private List<Function> childFun;//该父权限下的子权限 }
RoleFun
/**
* 角色权限
* @author Administrator
*
*/
public class RoleFun implements Serializable {
private Integer roleid;
private Integer funid;
}
3.下面看一下添加角色时是如何级联添加权限的
@RequestMapping(value="operRole",method=RequestMethod.POST)
public String addRole(HttpServletRequest request,Role role){
//获取权限id
String fids[]=request.getParameterValues("fids"); //添加角色表并级联角色权限表
roleService.addRoleFuns(role,fids ); return "redirect:toPage/listRole";
}
4.下面看一下上面方法中roleService.addRoleFuns(role,fids );调用的服务层的代码
public void addRoleFuns(Role role,String[] fids){ //添加角色表
roleDao.addRole(role); //定义角色权限
List<RoleFun> roleFuns=new ArrayList<RoleFun>();
//迭代添加角色权限
for (int i = 0; i < fids.length; i++) {
roleFuns.add(new RoleFun(role.getRid(), Integer.parseInt(fids[i])));
}
//添加角色权限表
roleFunDao.addRoleFun(roleFuns);
}
5.现在省略其中调用的模型层的代码,看一下Mybatis中相应的sql
a.添加角色(role.xml)
<!-- 添加角色 -->
<insert id="insert" parameterType="Role" useGeneratedKeys="true" keyProperty="rid">
insert into role(rname,rdesc) values(#{rname},#{rdesc})
</insert>
b.添加角色权限(rolefun.xml)
<!-- 添加角色权限 -->
<insert id="insert" >
insert into rolefun(roleid,funid) values
<foreach collection="list" item="rolefun" separator=",">
(#{rolefun.roleid},#{rolefun.funid})
</foreach>
</insert>
小结:Mybatis作为模型框架与Hibernate在级联添加多对多这样的关系对象的区别:
1.在定义POJO上:
a.Hibernate需要关联的双方在自己的类中用集合定义关联对象的关系,如在定义Role(角色)类时,就要定义:private Set<Function> = new HashSet<Function>();
在定义Function(权限)类时,就要定义:private Set<Role> = new HashSet<Role>();Mybatis不需要。
b.Hibernate不需要定义中间类(如RoleFun类);Mybatis需要。
2.在映射文件上:
Hibernate需要在各自的映射文件中定义与关联对象的关系;而Mybatis则不需要。
3.在添加方式上:
Hibernate调用Set方法将关联实例赋值,然后在添加时Hibernate会自动地级联添加关联对象;Mybatis是手工添加本对象及关联对象。
后记:Mybatis与Hibernate在级联查询、修改、删除对象的方式也是不同的,本博客不再赘述,以后再写。
Mybatis 一对一、一对多、多对多关联之级联添加的更多相关文章
- mybatis 一对一 一对多 多对多
一对一 一对多 多对多
- JPA级联(一对一 一对多 多对多)注解【实际项目中摘取的】并非自己实际应用
下面把项目中的用户类中有个:一对一 一对多 多对多的注解对应关系列取出来用于学习 说明:项目运行正常 问题类:一对多.一对一.多对多 ============一对多 一方的设置 @One ...
- Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作
Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作,单表查询,多表查询 一丶表与表之间的关系 背景: 由于如果只使用一张表存储所有的数据,就会操作数 ...
- 使用NHibernate(7)-- 一对一 && 一对多 && 多对多
1, 一对一. 对于数据量比较大的时候,考虑查询的性能,肯能会把一个对象的属性分到两个表中存放:比如用户和用户资料,经常使用的一般是Id和用户名,用户资料(学校,籍贯等)是不经常被查询的,所以就会分成 ...
- day 69-70 一对一 一对多 多对一联表查询
day 69 orm操作之表关系,多对多,多对一 多对一/一对多, 多对多{类中的定义方法} day69 1. 昨日内容回顾 1. 单表增删改查 2. 单表查询API 返回QuerySet对象的: 1 ...
- SQLAlchemy_定义(一对一/一对多/多对多)关系
目录 Basic Relationship Patterns One To Many One To One Many To Many Basic Relationship Patterns 基本关系模 ...
- JPA 一对一 一对多 多对一 多对多配置
1 JPA概述 1.1 JPA是什么 JPA (Java Persistence API) Java持久化API.是一套Sun公司 Java官方制定的ORM 方案,是规范,是标准 ,sun公司自己并没 ...
- MyBatis的关联关系 一对一 一对多 多对多
一对一示例 一个妻子对应一个丈夫 数据库表设计时 在妻子表中添加一个丈夫主键的作为外键 1 对应的JavaBean代码虽然在数据库里只有一方配置的外键,但是这个一对一是双向的关系. Husband实体 ...
- MyBatis 一对多,多对一关联查询的时候Mapper的顺序
要先写association,然后写collection:这是由DTD决定的: <resultMap ...> <association ...> </associati ...
随机推荐
- 是时候全面使用html5标签了
html5,这个词语,不管是业内还是业外,都已经耳熟能详了.因为已经火了这么长的的时间了.但是,真正开始使用的又有多少人呢?只能用呵呵来形容了! html5真的来了 2014年10月28日,历经八年, ...
- 和阿文一起学H5--如何把H5压缩到最小
三种压缩图片的方法: 1.PS 但是PS每次只能压缩一张,下面介绍第二个神器 2.TinyPng压缩 https://tinypng.com/ 3.IloveIMG压缩 http://www.ilov ...
- DOS批处理命令-引数取得
参数传递对程序来说,是一个很重要的事情,所以,获得传递的参数是很重要的,接下来,我们来探讨下获得传递的参数的N种方式. 1.%N 获得传递的第N个参数(N最大为9) 就是传递过去的参数原样值(并且忽 ...
- WebService中控制字符的处理
情景 最近项目中很多WebService都发不出去,报的错误如下: Invalid white space character in text to output (in xml 1.1 ...
- (转)实战Memcached缓存系统(4)Memcached的CAS协议
1. 什么是CAS协议 很多中文的资料都不会告诉大家CAS的全称是什么,不过一定不要把CAS当作中国科学院(China Academy of Sciences)的缩写.Google.com一下,CAS ...
- 清理c盘垃圾(将一下代码复制到记事本然后把后缀名改为xxx.bat,然后双击,就ok了!!)
@echo off echo 正在清除系统垃圾文件,请稍等...... del /f /s /q %systemdrive%\*.tmp del /f /s /q %systemdrive%\*._m ...
- 【转载】分享下多年积累的对JAVA程序员成长之路的总结
注:该文是从百度贴吧转载过来,之前看到觉得写得还不错,对Java开发学习者来说很有意义的,可以看看. 我也搞了几年JAVA了,由于一向懒惰,没有成为大牛,只是一普通程序猿,不爱玩社交网站,不爱玩微博, ...
- 动态linq表达式新方法,Dynamic LINQ Extension Method
Remember those old posts on Dynamic LINQ? You are probably aware that Microsoft has made its impleme ...
- prototype原型理解
一切都是对象,对象是若干属性的集合 数组是对象.函数是对象.对象还是对象.对象里面的一切都是属性,只有属性,没有方法.方法也是属性. 一切引用类型都是属性 怎么判断一个值是否是对象? 值类型的类型 ...
- position containing block原点
如果元素有属性 'position:absolute',containing block 由最近的 position 不是 static 的祖先建立,按下面的步骤: 1.如果祖先是块级元 ...