0

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?

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

I have tried this solution, but it doesn't work - it doesn't save the courses of the user. There's also no error when I submit the form.
I tested your entities locally and I can see the SQL fired and it works, I don't see any other issue in your code. Try turning on your logs and see if queries are fired or not.
Well I think there's something wrong with the add function , because my logs show me that I get these course titles from the jsp form, however they don't get added to newUser
Yes, you're right the add function is working fine, but when I turned on Hibernate logs , this Hibernate: insert into course (id, title, user_id) values (null, ?, ?) insert line doesn't appear. I will try to find where the problem may be. Thanks for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.