8.MyBatis 的关联映射

8.1关联映射的概念

在关系型数据库中,多表之间存在三种关联关系,分别为一对一,一对多,多对多。
在数据库中的表现:

  • 一对一:在任意一方引入对方主键作为外键

  • 一对多:在“多”的一方引入“一”的一方作为主键

  • 多对多:产生中间关系表,引入两个表的主键作为外键,两个主键成为联合 主键或使用新的字段作为主键。
    在Java实现时的表现:

  • 一对一:在本类中定义对方类型的对象

  • 一对多:一个A类型对应多个B类型,在A类中以集合的方式引入B类型,在B类中定义A类型的属性a

  • 多对多:均定义对方类型的集合

8.2一对一

案例:每个人都有唯一的身份证
创建好对应的数据库,然后创建对应的实体类,以及对应的get和set方法

public class IdCard {
	private Integer id;
	private String code;
}
public class Person {
	private Integer id;
	private String name;
	private Integer age;
	private String sex;
	private IdCard card;
}

为了实现一对一查询,总共有两种方法,一个是嵌套查询,一个是嵌套结果
方法一:嵌套查询
相当于需要编写两个SQl语句,首先创建IdCardMapper,编写findCardById

<mapper namespace="com.itheima.mapper.IdCardMapper">
	<!-- 根据卡号查询-->
	<select id="findCardById" parameterType="Integer"
		resultType="com.itheima.po.IdCard">
		select * from tb_idcard where id = #{id}
	</select>
</mapper>

然后编写

<mapper namespace="com.itheima.mapper.PersonMapper">
	<!-- 根据卡号查询-->
	<select id="findPersonById" parameterType="Integer"
		resultMap="IdCardWithPersonResult">
		select * from tb_person where id = #{id}
	</select>
	<resultMap type="Person" id="IdCardWithPersonResult">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="age" column="age"/>
		<result property="sex" column="sex"/>
		<association property="card" column="card_id" javaType="IdCard"
					 select="com.itheima.mapper.IdCardMapper.findCardById"></association>
	</resultMap>
</mapper>

在association元素中,
property对应实体类对象属性
column对应表中的字段
javaType对应实体类的类型
select对应嵌套的子查询语句
方法二:嵌套结果

<select id="findPersonById2" parameterType="Integer"
		resultMap="IdCardWithPersonResult2">
		select p.*,idcard.code
		from tb_person p,tb_idcard idcard
		where p.card_id=idcard.id and p.id = #{id}
	</select>
	<resultMap type="Person" id="IdCardWithPersonResult2">
	<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="age" column="age"/>
		<result property="sex" column="sex"/>
		<association property="card" javaType="IdCard">
			<id property="id" column="card_id" />
			<result property="code" column="code"/>
		</association>
	</resultMap>

编写测试方法,运行
方法一8.MyBatis 的关联映射

方法二
8.MyBatis 的关联映射

8.3一对多

案列:一个顾客有多个订单
编写测试数据库,编写实体类,并在顾客实体类中定义订单列表

public class Orders {
	private Integer id;
	private String number;
	}
public class User {
	private Integer id;
	private String username;
	private String address;
	private List<Orders> orderlist;
}

编写查询方法

<mapper namespace="com.itheima.mapper.UserMapper">
	<select id="findUserWithOrders" parameterType="Integer"
		resultMap="UserWithOrderResult">
		select u.*,o.id as orders_id,o.number
		from tb_user u,tb_orders o
		where u.id=o.user_id and u.id = #{id}
	</select>
	<resultMap type="User" id="UserWithOrderResult">
		<id property="id" column="id"/>
		<result property="username" column="username"/>
		<result property="address" column="address"/>
		<collection property="orderlist" ofType="Orders">
			<id property="id" column="orders_id" />
			<result property="number" column="number"/>
		</collection>
	</resultMap>

这里与上一个不同的属性时ofType
编写测试方法测试
8.MyBatis 的关联映射
在测试过程中,出现错误

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.itheima.mapper.PersonMapper.UserMapper.findUserWithOrders
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.itheima.mapper.PersonMapper.UserMapper.findUserWithOrders
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77)
	at com.itheima.test.MyBatisAssTest.findUser(MyBatisAssTest.java:39)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12).
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.itheima.mapper.PersonMapper.UserMapper.findUserWithOrders
	at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:875)
	at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:708)
	at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:701)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
	... 26 more

这种情况有四种可能性;

1、mapper.xml中没有加入namespace
2、mapper.xml中的方法和接口mapper的方法不对应
3、mapper.xml没有加入到mybatis-config.xml中(即总的配置文件),例外:配置了mapper文件的包路径的除外
4、mapper.xml文件名和所写的mapper名称不相同
但是我的问题是,com.itheima.mapper.UserMapper.findUserWithOrders路径写错了。
所以大家一定要仔细。

8.4多对多

案例:一个商品对应多个订单,一个订单包含多个商品

编写测试数据库,编写实体类,两个实体类中都需要添加列表

public class Orders {
	private Integer id;
	private String number;
	private List<Product> productList;
}
public class Product {
	private Integer id;
	private String name;
	private Double price;
	private List<Orders> orders;
}

编写多表查询的语句

<mapper namespace="com.itheima.mapper.OrdersMapper">
	<select id="findProductWithOrders" parameterType="Integer"
		resultMap="ProductWithOrderResult">
		select o.*,p.id as pid,p.name,p.price
		from tb_orders o,tb_product p,tb_ordersitem oi
		where o.id=oi.orders_id
		and p.id=oi.product_id
		and o.id = #{id}
	</select>
	<resultMap type="Orders" id="ProductWithOrderResult">
		<id property="id" column="id"/>
		<result property="number" column="number"/>
		<collection property="productList" ofType="Product">
			<id property="id" column="pid" />
			<result property="name" column="name"/>
			<result property="price" column="price"/>
		</collection>
	</resultMap>
</mapper>

运行测试如下:
8.MyBatis 的关联映射

上一篇:redis集群创建错误的解决方法


下一篇:NETSCOUT宣布推出Omnis Cyber Intelligence解决方案