简体   繁体   中英

How to configure xml mapper to insert entity with collection property in mybatis

I am starting to learn myBatis concepts, and I'm trying to make an simple (or not that simple) insert configuration in xml. I have an application in java that reads, inserts and updates some books against the dataBase. The xml confguration for connections with the db is already done.

In java I have 2 simple Pojo's :

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

}

and

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;
    }

}

And here is the xml config for the query :

 <?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> 

I have also a class called DBBookDao that implements all the proper methods such as "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);

    }

}

In database I have 2 different tables : -"TAB_PRODUCTS" table where I'm keeping information about the book , with 3 col : PROD_ID,NAME,DESCRIPTION, - "TAB_AUTHORS" table where I'm keeping information about the author,with 3 col : AUT_ID, NAME, DESCRIPTION.

I managed to succesfully implement the realAll() AND findByName() methods, I'm not confortable with the insert procedure.

Is there a nested insert? How do i configure the insert confoguration in xml to accept a list of an authors inside the book?

You can generate insert statements using foreach element like this:

<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>

Note that you there's no description field in you author class so you need to specify correct value there, and also I don't know what is the sequence name for author identifiers, so this is a draft to illustrate the idea.

Alternatively, you can iterate over the authors list in the 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);
    }
}

You would need to create a mapper method insertAuthor (or have another mapper for authors).

Side note : don't check for one element existing by querying all objects from the database like you do in checkBookExists . Base it on findByName method instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM