Reputation: 103
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:
and
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
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