示例项目: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 一对一、一对多、多对多关联之级联添加的更多相关文章

  1. mybatis 一对一 一对多 多对多

    一对一 一对多 多对多

  2. JPA级联(一对一 一对多 多对多)注解【实际项目中摘取的】并非自己实际应用

    下面把项目中的用户类中有个:一对一  一对多  多对多的注解对应关系列取出来用于学习      说明:项目运行正常 问题类:一对多.一对一.多对多 ============一对多 一方的设置 @One ...

  3. Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作

    Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作,单表查询,多表查询 一丶表与表之间的关系 背景: ​ ​ ​  ​ ​ 由于如果只使用一张表存储所有的数据,就会操作数 ...

  4. 使用NHibernate(7)-- 一对一 && 一对多 && 多对多

    1, 一对一. 对于数据量比较大的时候,考虑查询的性能,肯能会把一个对象的属性分到两个表中存放:比如用户和用户资料,经常使用的一般是Id和用户名,用户资料(学校,籍贯等)是不经常被查询的,所以就会分成 ...

  5. day 69-70 一对一 一对多 多对一联表查询

    day 69 orm操作之表关系,多对多,多对一 多对一/一对多, 多对多{类中的定义方法} day69 1. 昨日内容回顾 1. 单表增删改查 2. 单表查询API 返回QuerySet对象的: 1 ...

  6. SQLAlchemy_定义(一对一/一对多/多对多)关系

    目录 Basic Relationship Patterns One To Many One To One Many To Many Basic Relationship Patterns 基本关系模 ...

  7. JPA 一对一 一对多 多对一 多对多配置

    1 JPA概述 1.1 JPA是什么 JPA (Java Persistence API) Java持久化API.是一套Sun公司 Java官方制定的ORM 方案,是规范,是标准 ,sun公司自己并没 ...

  8. MyBatis的关联关系 一对一 一对多 多对多

    一对一示例 一个妻子对应一个丈夫 数据库表设计时 在妻子表中添加一个丈夫主键的作为外键 1 对应的JavaBean代码虽然在数据库里只有一方配置的外键,但是这个一对一是双向的关系. Husband实体 ...

  9. MyBatis 一对多,多对一关联查询的时候Mapper的顺序

    要先写association,然后写collection:这是由DTD决定的: <resultMap ...> <association ...> </associati ...

随机推荐

  1. tomcat 安装

    升级系统之后很长一段时间没有用tomcat(主要是没做东西),这两天要开始干活了,发现竟然没法发用了....ok,重新整一遍.算是温习. 上次所有环境的搭建基本都是师兄帮我,自己做得东西很少,这次就正 ...

  2. ORACLE 小写金额转大写金额

    Create Or Replace Function Money2Chinese(Money In Number) Return Varchar2 Is strYuan Varchar2(); str ...

  3. cv::mat转换成QImage的问题

    在进行cv::mat转换为QImage过程中,经常出现问题: cv::Mat image; ...QImage img=QImage((const unsigned char*)(image.data ...

  4. 使用ptrace向已运行进程中注入.so并执行相关函数

    这个总结的很好,从前一个项目也用到这中技术 转自:http://blog.csdn.net/myarrow/article/details/9630377 1. 简介 使用ptrace向已运行进程中注 ...

  5. Could not load the "defaultimg" image referenced from a nib in the bundle with identifier "com.abc"

    出现这个错误提示,是因为在xib中使用了.jpg格式的图片,在图片名称后面加上.jpg即可;

  6. Quartz.NET快速上手第一课(官网文档翻译)

    Quartz.NET快速上手第一课(官网文档翻译) 原文链接 在你使用调度者(scheduler)之前,你需要对它进行实例化(谁能猜到这呢?).在实例化scheduler时候,你需要使用ISchedu ...

  7. (转)实战Memcached缓存系统(3)Memcached配置参数初解

    一.基本参数 在我们第一次安装Memcached时,一般都是用过这个命令: memcached -m 512 -u root -d -l 127.0.0.1 -p 11211 我们先来解释这几个参数的 ...

  8. js及jQuery实现checkbox的全选、反选和全不选

    html代码: <label><input type="checkbox" id="all"/>全选</label> < ...

  9. java进阶一之jdk8新特性

    1.官方发布的jdk8新特性 2.51CTO相关专题

  10. 3月3日(2) Search Insert Position

    这题...有点简单吧,为什么只有34%的通过率? 题目意思简单说就是查找index,或者按升序插入的未知,WA一次,罪过,下次要特别注意程序里变量的变化,提交前用样例检查. 简单的我有点不好意思贴代码 ...