示例項目: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在級聯查詢、修改、刪除對象的方式也是不同的,本博客不再贅述,以后再寫。