Mybatis实现联合查询(六)
1. 疑问
在之前的章节中我们阐述了如何用Mybatis实现检查的查询,而我们实际的需求中,绝大部分查询都不只是针对单张数据表的简单查询,所以我们接下来要看一下Mybatis如何实现联合查询。
2. 数据库准备
--销售单表 CREATE TABLE tbSaleM ( ID INT IDENTITY(1,1), SaleDate DATETIME, --销售日期 ClientName NVARCHAR(200), --客户名称 AmountSum NUMERIC(16,4), --销售数量汇总 MoneySum NUMERIC(16,4), --销售金额汇总 PRIMARY KEY (ID) --主键 ) --销售明细表 CREATE TABLE tbSaleD ( ID INT IDENTITY(1,1), MID INT, --对应销售单表的ID PartID INT, --商品ID,在我们之前建立的商品信息表里 SaleAmount NUMERIC(16,4), --销售数量 SalePrice NUMERIC(16,4), --销售单价 SaleMoney NUMERIC(16,4) --销售金额 PRIMARY KEY (MID, PartID) --主键 )
我们建立两个数据表来记录一个完整的销售过程。tbSaleM记录销售日期、客户名称的主要单据信息,tbSaleD用来记录具体销售了哪些商品。其中tbSaleD的MID取值为tbSaleM中的ID,tbSaleD中的Part取值为之前章节中tbInfoPart的ID。
然后我们生成一条用来测试的销售数据:
DECLARE @LastID INT INSERT INTO tbSaleM (SaleDate, ClientName, AmountSum, MoneySum) VALUES (GETDATE(), '张三', 3, 4998.800000) SET @LastID=@@IDENTITY INSERT INTO tbSaleD (MID, PartID, SaleAmount, SalePrice, SaleMoney) VALUES (@LastID, 1, 2, 1099.900000, 1099.900000*2) INSERT INTO tbSaleD (MID, PartID, SaleAmount, SalePrice, SaleMoney) VALUES (@LastID, 2, 1, 2799.000000, 2799.000000*1)
3. 采购单实体类的建立
1)销售单表(注意这里面有一个的saleDs属性):
package com.mybatis.entity; import java.util.Date; import java.util.List; public class SaleM { private Integer id; private Date saleDate; private String clientName; private Float amountSum; private Float moneySum; private List<SaleD> saleDs; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Date getSaleDate() { return saleDate; } public void setSaleDate(Date saleDate) { this.saleDate = saleDate; } public String getClientName() { return clientName; } public void setClientName(String clientName) { this.clientName = clientName; } public Float getAmountSum() { return amountSum; } public void setAmountSum(Float amountSum) { this.amountSum = amountSum; } public Float getMoneySum() { return moneySum; } public void setMoneySum(Float moneySum) { this.moneySum = moneySum; } public List<SaleD> getSaleDs() { return saleDs; } public void setSaleDs(List<SaleD> saleDs) { this.saleDs = saleDs; } }
2)销售明细表(注意这里面的partInfo属性)
package com.mybatis.entity; public class SaleD { private Integer id; private Integer mId; private Integer partId; private Float saleAmount; private Float salePrice; private Float saleMoney; private PartInfo partInfo; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getmId() { return mId; } public void setmId(Integer mId) { this.mId = mId; } public Integer getPartId() { return partId; } public void setPartId(Integer partId) { this.partId = partId; } public Float getSaleAmount() { return saleAmount; } public void setSaleAmount(Float saleAmount) { this.saleAmount = saleAmount; } public Float getSalePrice() { return salePrice; } public void setSalePrice(Float salePrice) { this.salePrice = salePrice; } public Float getSaleMoney() { return saleMoney; } public void setSaleMoney(Float saleMoney) { this.saleMoney = saleMoney; } public PartInfo getPartInfo() { return partInfo; } public void setPartInfo(PartInfo partInfo) { this.partInfo = partInfo; } }
4. 销售单的查询
我们知道,如果是在SQL中查询这个销售单,应该这样查询:
SELECT A.ID AS AID, A.SaleDate, A.ClientName, A.AmountSum, A.MoneySum, B.ID AS BID, B.MID, B.PartID, B.SaleAmount, B.SalePrice, B.SaleMoney, C.ID As CID, C.PartCode, C.PartName, C.SalePrice AS CSalePrice, C.Unit FROM tbSaleM A INNER JOIN tbSaleD B ON A.ID=B.MID INNER JOIN tbInfoPart C ON B.PartID=C.ID WHERE A.ID=1
然后我们需要Mybatis将这个查询结果填充到SaleM的实体类中,那么Mybatis中应该怎么配置呢?
1) 首先我们仍然需要在com.mybatis.dao.PartDao中增加一个接口函数:
/** * 查询销售单 * @param id 要查询的销售单ID * @return 返回销售单信息 */ public SaleM getSaleM(int id);
2) 相对应的在PartMapper中需要增加此接口函数的实现,配置如下:
<!-- 注意这里不是resultType,而是resultMap,其取值SaleM来源为下面resultMap标签中的id属性 --> <select id="getSaleM" parameterType="int" resultMap="SaleM"> SELECT A.ID AS AID, A.SaleDate, A.ClientName, A.AmountSum, A.MoneySum, B.ID AS BID, B.MID, B.PartID, B.SaleAmount, B.SalePrice, B.SaleMoney, C.ID As CID, C.PartCode, C.PartName, C.SalePrice AS CSalePrice, C.Unit FROM tbSaleM A INNER JOIN tbSaleD B ON A.ID=B.MID INNER JOIN tbInfoPart C ON B.PartID=C.ID WHERE A.ID=#{id} </select> <resultMap type="com.mybatis.entity.SaleM" id="SaleM"> <id property="id" column="AID"/> <result property="saleDate" column="SaleDate"/> <result property="clientName" column="ClientName"/> <result property="amountSum" column="AmountSum"/> <result property="moneySum" column="MoneySum"/> <collection property="saleDs" ofType="com.mybatis.entity.SaleD"> <id property="id" column="BID"/> <result property="mId" column="MID"/> <result property="partId" column="PartID"/> <result property="saleAmount" column="SaleAmount"/> <result property="salePrice" column="SalePrice"/> <result property="saleMoney" column="SaleMoney"/> <association property="partInfo" javaType="com.mybatis.entity.PartInfo"> <id property="id" column="CID"/> <result property="partCode" column="PartCode"/> <result property="partName" column="PartName"/> <result property="salePrice" column="CSalePrice"/> <result property="unit" column="Unit"/> </association> </collection> </resultMap>
3) 测试下查询结果
public static void main(String[] args) { InputStream iStream = TestMain.class.getClassLoader().getResourceAsStream("mybatis.xml"); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(iStream); SqlSession session = sessionFactory.openSession(); String statement = "com.mybatis.dao.PartDao.getSaleM"; SaleM saleM = session.selectOne(statement, 1); session.commit(); session.close(); System.out.println("销售"+saleM.getId()+":"+ saleM.getClientName()+" 于 "+ saleM.getSaleDate()+ " 购买了共"+saleM.getAmountSum()+ "件商品,总售价:"+saleM.getMoneySum()+"元"); System.out.println("其中包含:"); for (SaleD saleD : saleM.getSaleDs()) { System.out.println("----["+ saleD.getPartInfo().getPartName()+"] "+ saleD.getSaleAmount()+ saleD.getPartInfo().getUnit()+",单价"+ saleD.getSalePrice()+",共"+ saleD.getSaleMoney()+"元"); } }
打印结果为:
销售1:张三 于 Sun Feb 21 14:03:24 CST 2016 购买了共3.0件商品,总售价:4998.8元 其中包含: ----[TCL D32E161 32英寸 内置wifi 在线影视 窄边LED网络液晶电视] 2.0台,单价1099.9,共2199.8元 ----[TCL D50A710 50英寸 40万小时视频 全高清 内置WiFi 八核安卓智能LED液晶电视] 1.0台,单价2799.0,共2799.0元
5. resultMap释义
collection:实现1对多关联, association :实现1对1关联。
result:规定了查询结果列和JavaBean的对应关系,其中property为JavaBean的属性名,column为查询结果列名。
id:功能同result,但是标记为id可以帮助提高整理性能。