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可以帮助提高整理性能。

6. 目录结构

QQ截图20160221150751

笔者只是初学者,开此博客的初衷是为了给自己的学习过程留一个痕迹。所以您可能发现笔者措辞不严谨、逻辑不合理,甚至代码有错误、结论很偏颇等等。笔者感激各位的讨论和指正,并在此不胜感激!拜谢!欢迎加QQ群讨论:852410026
原文地址:https://www.cnblogs.com/LOVE0612/p/5204958.html