如何配置xml映射器以在mybatis中插入具有collection属性的实体

时间:2018-12-11 11:35:23

标签: java mybatis

我开始学习myBatis概念,并且尝试在xml中进行简单(或不那么简单)的插入配置。 我有一个Java应用程序,可以针对数据库读取,插入和更新一些书。 与数据库连接的xml配置已经完成。

在Java中,我有2个简单的Pojo:

public class Book {
    private Long id;
    private String name;
    private List<Author> authors;
    private String desc;

    public Book() {
        //Default Constructor
    }

    //constructors that takes args, setters & getters

}

public class Author {

    private String authorName;
    public Author() {
        // Default Constructor
    }
    public Author(String authorName) {
        this.authorName = authorName;
    }
    public String getAuthorName() {
        return authorName;
    }
    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

}

这是查询的xml配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kepler.learning.mybooks.dao.BookDao">

	<resultMap id="BookResult" type="Book">
		<id property="id" column="id"></id>
		<result property="name" column="name"></result>
		<result property="desc" column="desc"></result>
		<collection property="authors" ofType="Author">
			<result property="authorName" column="authorName"></result>
		</collection>
	</resultMap>
	<select id="readAll" resultMap="BookResult">
	    SELECT b.prod_id "id", b.name, a.name "authorName", b.description "desc"
		FROM tab_products b
			left outer join tab_authors a on b.PROD_ID = a.AUT_ID
	</select>
	
	<select id="findByName" parameterType="String" resultMap="BookResult">
	    SELECT b.prod_id "id", b.name, a.name "authorName", b.description "desc"
		FROM tab_products b
			left outer join tab_authors a on b.PROD_ID = a.AUT_ID
		WHERE b.name = #{name}
	</select>
	<insert id="insert" parameterType="Book">
		  INSERT INTO tab_products(prod_id,name,description)
      VALUES(SEQ_PRD_ID.nextVal,#{name},#{desc});
	</insert>
	
</mapper>

我还有一个名为DBBookDao的类,该类实现所有适当的方法,例如“ read all”,“ findByName”,“ insert”:

public class DBBookDao implements BookDao{
    private String resource = "mybatis.config.xml";
    private InputStream inputStream;
    private SqlSession sqlSession;
    private SqlSessionFactory sqlSessionFactory;
    public DBBookDao() {
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            throw new BusinessException(e);
        }
    }

    public List<Book> readAll() {
        try {
            sqlSession = sqlSessionFactory.openSession();
            return sqlSession.selectList("com.kepler.learning.mybooks.dao.BookDao.readAll");
        } finally {
            sqlSession.close();
        }
    }

    public Book findByName(String name) {
        if (name == null) {
            throw new BusinessException("No book name provided!");
        }

        try {
            sqlSession = sqlSessionFactory.openSession();
            List<Book> books = sqlSession.selectList("com.kepler.learning.mybooks.dao.BookDao.findByName", name);

            return Optional.ofNullable(books).map(list -> list.get(0)).orElse(null);
        }
        finally {
            sqlSession.close();
        }

    }

    public boolean checkBookExists(Book book) {
        List<Book> allBooks = readAll();
        for(Book b : allBooks) {
            if(b.getName().equals(book.getName())) {
                return true;
            }
        }
        return false;
    }

    public void insert(Book book) {

        sqlSession = sqlSessionFactory.openSession();
        sqlSession.insert("com.kepler.learning.mybooks.dao.BookDao.insert",book);

    }

}

在数据库中,我有2个不同的表: -“ TAB_PRODUCTS”表,其中保存有关该书的信息,并带有3列:PROD_ID,NAME,DESCRIPTION, -在“ TAB_AUTHORS”表中保存有关作者的信息,并带有3列 :AUT_ID,名称,DESCRIPTION。

我成功地实现了realAll()和findByName()方法,但我对插入过程并不满意。

是否有嵌套插入?如何在xml中配置插入配置以接受书中的作者列表?

1 个答案:

答案 0 :(得分:0)

您可以使用foreach元素生成插入语句,如下所示:

<insert id="insert" parameterType="Book">
    INSERT INTO tab_products(prod_id,name,description)
  VALUES(SEQ_PRD_ID.nextVal,#{name},#{desc});
    <foreach collection="authors" item="author" index="index">
       INSERT INTO tab_authors(aut_id,name,description)
  VALUES(SEQ_AUT_ID.nextVal,#{author.authorName},#{author.whateverDescProperty});
    </foreach>
</insert>

请注意,您的作者类中没有描述字段,因此您需要在其中指定正确的值,而且我也不知道作者标识符的序列名称是什么,因此,这是用于说明此想法的草案。 / p>

或者,您可以遍历DAO中的作者列表:

public void insert(Book book) {

    sqlSession = sqlSessionFactory.openSession();
    sqlSession.insert("com.kepler.learning.mybooks.dao.BookDao.insert",book);
    for(Author author:book.getAuthors()) {
       sqlSession.insert(
         "com.kepler.learning.mybooks.dao.BookDao.insertAuthor",
         author);
    }
}

您需要创建一个映射器方法insertAuthor(或为作者提供另一个映射器)。

旁注:不要像在checkBookExists中那样通过查询数据库中的所有对象来检查是否存在一个元素。而是基于findByName方法。