NewJavaEnthusiast
NewJavaEnthusiast

Reputation: 103

How to insert List of Objects, which contains an Array of Strings into database table, using Hibernate & JPA?

Hey guys I am learning Hibernate Mappings and JPA, without using Spring. I've stumbled upon a task which I can't do.

I have two database tables:

main_table

and

secondary_table

Each user can sign for multiple courses.

My java code is:

User

@Entity
@Table(name="users")
public class User {
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id;
    
    @Column(name="name")
    private String name;
    
    @Column(name="email")
    private String email;
    
    @Column(name="country")
    private String country; 

    
    @OneToMany(fetch = FetchType.EAGER, 
            mappedBy = "user", 
            cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
    private List<Course> courses;
    
    public User() {
    }
    
    public User(String name, String email, String country) {
        this.name = name;
        this.email = email;
        this.country = country;
    }

    public User(int id, String name, String email, String country) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.country = country;
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getCountry() {
        return country;
    }
    public void setCountry(String country) {
        this.country = country;
    }
    
    
    public List<Course> getCourses() {
        return courses;
    }

    public void setCourses(List<Course> courses) {
        this.courses = courses;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", email=" + email + ", country=" + country 
                + ", userDetail=" + userDetail
                + "]";
    }
    
    public void add(Course tempCourse) {        
        if (courses == null) {
            courses = new ArrayList<>();
        }       
        courses.add(tempCourse);
        
        tempCourse.setUser(this);
    }
}

Course

@Entity
@Table(name="course")
public class Course {
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id;
    
    @Column(name="title")
    private String title;
    
    @ManyToOne(cascade= {CascadeType.PERSIST, CascadeType.MERGE,
                         CascadeType.DETACH, CascadeType.REFRESH})
    @JoinColumn(name="user_id")
    private User user;
    
    public Course() {
        
    }

    public Course(String title) {
        this.title = title;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Course [id=" + id + ", title=" + title + "]";
    }   
}

UserDao

public class UserDao {
    
    /**
     * Save User
     * @param user
     */
    public void saveUser(User user) {
        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            // start a transaction
            transaction = session.beginTransaction();
            // save the student object
            session.save(user);
            // commit transaction
            transaction.commit();
            
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } 
    }

    /**
     * Get User By ID
     * @param id
     * @return
     */
    public User getUser(int id) {

        Transaction transaction = null;
        User user = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            // start a transaction
            transaction = session.beginTransaction();
            // get an user object
            user = session.get(User.class, id);
            // commit transaction
            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }
        return user;
    }
}

and UserServlet

@WebServlet("/")
public class UserServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private UserDao userDao;
    
    
    public void init() {
        userDao = new UserDao();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String action = request.getServletPath();

        try {
            switch (action) {
            case "/new":
                showNewForm(request, response);
                break;
            case "/insert":
                insertUser(request, response);
                break;
            default:
                listUser(request, response);
                break;
            }
        } catch (SQLException ex) {
            throw new ServletException(ex);
        }
    }

    private void showNewForm(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        RequestDispatcher dispatcher = request.getRequestDispatcher("user-form.jsp");
        dispatcher.forward(request, response);
    }

    private void insertUser(HttpServletRequest request, HttpServletResponse response) 
            throws SQLException, IOException {
        String name = request.getParameter("name");
        String email = request.getParameter("email");
        String country = request.getParameter("country");
        
        int age = Integer.parseInt(request.getParameter("age"));
        String hobby = request.getParameter("hobby");

        
        String[] courseTitleArray = request.getParameterValues("courseTitle");
        
        User newUser = new User(name, email, country);
        UserDetail userDetail = new UserDetail(age, hobby);
        newUser.setUserDetail(userDetail);
        
        userDao.saveUser(newUser);
        response.sendRedirect("list");
    }
}

and finally the UserForm jsp

<h1>Add New User</h1>
<div align="center">
    <form action="insert" method="post">
        <table class="table table-sm" style="width: 30%;">          
            <tr>
                <td>User Name: </td>
                <td>
                    <input type="text" name="name" />
                </td>
            </tr>
            <tr>
                <td>User Email: </td>
                <td>
                    <input type="text" name="email" />
                </td>
            </tr>
            <tr>
                <td>Country: </td>
                <td>
                    <input type="text" name="country" />
                </td>
            </tr>            
            <tr>
                <td>                
                    <div id="coursesOutterDiv">
                        <label for="phoneNumber">User's Courses</label>
                            <div id="courseInnerDiv">
                                <input type="text" name="courseTitle" placeholder="Course title..." />      
                            </div>
                    </div>
                    <br/>
                    <div class="btnsDiv" style="margin-top: 5px;">
                         <input type="button" class="btn btn-sm btn-success" onclick="AddCourses()" value="Add Courses" />
                    </div>          
                </td>            
            </tr>
            
            
            <tr>
                <td colspan="2" align="center">
                    <input type="submit" value="Save" />
                </td>
            </tr>
        </table>
    </form>
</div>

<script>
$(document).ready(function () {
    $(document).on('click', '.course-remove', function () {
        $(this).closest('.courseInnerDivClass').remove();
    });
});

function AddCourses() {
    let counterCourses = $(".courseInnerDivClass").length;
    let nextCourse = 0;
    if (counterCourses <= 2) {
        let coursesToAppend = 
        '<div id="courseInnerDiv' + nextCourse++ + '" class="courseInnerDivClass">' +
        '<input type="text" name="courseTitle' + '"class="courseNumInputFields" placeholder="Course title...">' +
        '<a href="javascript:void(0);" class="course-remove">'+
            '<i class="fas fa-times-circle fa-lg"></i>'+
        '</a>' +
        '</div>';
        $(coursesToAppend).appendTo("#coursesOutterDiv");
    } else {
        alert("LIMIT!");
    }
}
</script>

As you can see in the JSP you can add multiple course-titles for a new user. So my question is: How can I save the user with his/hers attributes and save the course/courses which he/she is signed for?

Upvotes: 0

Views: 4797

Answers (1)

code_mechanic
code_mechanic

Reputation: 1148

You just need to use the add function in your user class like this from servlet insertUser function

for ( String title : courseTitleArray) {
       Course c = new Course():
       c.setTitle(title);
       newUser.add(c);
}

your dao function already doing transaction so that should be enough.

EDIT: As commented out, the code posted here should not have any problem and I am adding here that entities are fine. Here is my test

class StackOverFlowTest extends EntityManagerTest {
    @Test
    void persistingCoursesWithUserShouldWork() {
        doInTransaction( em -> {
            User user = new User();
            user.setName("Some user");
            user.setEmail("[email protected]");

            String[] courses = new String[]{"Hibernate Course", "Spring JPA Course"};

            asList(courses).forEach(s -> {
                Course course = new Course();
                course.setTitle(s);
                user.add(course);
            });

            em.persist(user);
        });

        doInTransaction(em -> {
            User user = em.find(User.class, 1);
            Assertions.assertEquals(user.getCourses().size(), 2);
        });
    }
}

And doInTransaction() is just a higher order function performing the transaction.

protected void doInTransaction(Consumer<EntityManager> executeInTransaction) {
        EntityManager em = entityManagerFactory.createEntityManager();
        em.getTransaction().begin();

        executeInTransaction.accept(em);

        em.getTransaction().commit();
        em.close();
}

And this produces the queries as below:

Hibernate: insert into users (id, country, email, name) values (null, ?, ?, ?)
Hibernate: insert into course (id, title, user_id) values (null, ?, ?)
Hibernate: insert into course (id, title, user_id) values (null, ?, ?)
Hibernate: select user0_.id as id1_13_0_, user0_.country as country2_13_0_, user0_.email as email3_13_0_, user0_.name as name4_13_0_, courses1_.user_id as user_id3_6_1_, courses1_.id as id1_6_1_, courses1_.id as id1_6_2_, courses1_.title as title2_6_2_, courses1_.user_id as user_id3_6_2_ from users user0_ left outer join course courses1_ on user0_.id=courses1_.user_id where user0_.id=?

The only difference, I am using entity manager and your code have used session, so your add function is working fine. You have error somewhere else.

Note: I am using the entities as it is, did not change a bit. I hope it will help you find the issue.

Upvotes: 1

Related Questions