I have two entities Courses and CourseUser. Courses mapped with OneToMany annotation to a CourseUser. After i add a CourseUser in a list of CourseUsers in Course and update it, new row appears in table CourseUser but it doesn't mapped to a Courses. If i call toString of courseUsers list from courses after update it will be empty.
#Entity
#Table(name = "COURSES")
public class Courses{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "course_id")
private int course_id;
#Column(name = "course_name", nullable = false)
private String courseName;
#Autowired
#OneToMany(mappedBy = "course", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<CourseUser> courseUsers = new HashSet<>(0);
CourseUser entity:
#Entity
#Table(name = "COURSE_USERS",
uniqueConstraints = {#UniqueConstraint(columnNames = {"course_name", "user_name"})})
public class CourseUser {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ev_id")
private int ev_id;
#Column(name = "course_name", nullable = false)
private String courseName;
#Column(name = "user_name", nullable = false)
private String userName;
#Column(name = "course_role")
private String courseRole;
#Column(name = "grade")
private int grade ;
#ManyToOne
#JoinColumn(name = "course_id")
private Courses course;
this is how i add new courseUser to a course :
Courses course = courseDAO.getCourse(id);
Set<CourseUser> courseUsers = course.getCourseUsers();
CourseUser newUser = new CourseUser();
newUser.setUserName(name);
newUser.setCourseRole(role);
newUser.setCourseName(course.getCourseName());
courseUsers.add(newUser);
course.setCourseUsers(courseUsers);
update(course);
and here is CoursesDAO update method:
public void update(Courses course) {
Session session = sf.openSession();
Transaction transaction = session.beginTransaction();
session.merge(course);
session.flush();
transaction.commit();
session.close();
}
At first, you have to save entity, which is referenced by id.
In your case, you have to save CourseUser at first, and then add it to Course.
For example:
Courses course = courseDAO.getCourse(id);
Set<CourseUser> courseUsers = course.getCourseUsers();
CourseUser newUser = new CourseUser();
newUser.setUserName(name);
newUser.setCourseRole(role);
newUser.setCourseName(course.getCourseName());
// this row is very important
// after thus operation newUser will have an id to be referenced
courseUserDto.save(newUser);
courseUsers.add(newUser);
course.setCourseUsers(courseUsers);
update(course);
Also, there is some redundant code that you wrote:
Set<CourseUser> courseUsers = course.getCourseUsers();
// ...
course.setCourseUsers(courseUsers);
course already stores reference to courseUsers.
Related
I want to use check constraint to verify if there are more students in the subject more than vacancies. These are the entities:
SubjectOffer
#Entity
#SequenceGenerator(name = "SUBJECT_OFFER_SEQ", sequenceName = "SUBJECT_OFFER_SEQ")
#Table(name = "SUBJECT_OFFER", uniqueConstraints = {
#UniqueConstraint(name = "UQ_SUBJECT_OFFER_COURSE_SUBJECT_SEMESTER_CLASS", columnNames = {"COURSE_ID", "SUBJECT_ID", "SEMESTER", "CLASS_NUMBER"})})
#Check(constraints = "COUNT(STUDENT_SUBJECT_ID) <= VACANCIES")
public class SubjectOffer {
#Id
#GeneratedValue(generator = "SUBJECT_OFFER_SEQ")
#Column(name = "SUBJECT_OFFER_ID", nullable = false)
private Long id;
#OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
#JoinColumn(name = "STUDENT_SUBJECT_ID")
private Set<StudentSubject> studentSubjects = new HashSet<>();
//other attributes
#Column(name = "VACANCIES", nullable = false)
private int vacancies;
}
StudentSubject
#Entity
#Table(name = "STUDENT_SUBJECT")
public class StudentSubject {
#EmbeddedId
private StudentSubjectId id = new StudentSubjectId();
#MapsId("studentId")
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "STUDENT_ID", nullable = false)
private Student student;
#MapsId("subjectOfferId")
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "SUBJECT_OFFER_ID", nullable = false)
private SubjectOffer subjectOffer;
#Column(name = "SEMESTER", nullable = false)
private int semester;
#Column(name = "GRADE")
private BigDecimal grade;
}
I also tried column definition in Set #JoinColumn but it didn't work
SQL check constraints only work on a single table. What you want is a so called SQL assertion constraint, but no database implements that. The best you can do is to pre-create rows for the amount of vacancies and just assign students to these rows without ever creating more rows. This way, you can make sure that you only assign as many students as there are vacancies, given that you use optimistic/pessimistic locking when assigning a student.
Recently I got an issue I can't seem to figure out. I have entity class called order that has a one to one relationship with two other entity classes called Product and Customer. When I try to set the customer the foreign key is set in the database. However when I try to do the same thing with the product he doesn't do it. The customer is created in the database the moment when the order is made. But the product is retrieved from the database.
My apologies for the written code. This is the controller we use to save the entities to the mysql database
#RequestMapping(value = "/makeorder", method = RequestMethod.POST)
public String MakeOrder(#RequestBody String Json, RedirectAttributes ra) throws IOException {
List<Orders> o = new ArrayList<>();
String[] lijst = Json.split("r");
String[] naamsplit = Json.split("CustomerNaam" + "=");
String naam = naamsplit[1].substring(0, naamsplit[1].indexOf("&"));
naam = naam.replace("+", " ");
String[] adressplit = Json.split("CustomerAdres" + "=");
Customer customersaved = new Customer();
String adres = adressplit[1].substring(0, adressplit[1].indexOf("&"));
adres = adres.replace("+", " ");
if (naam != "" && adres != "") {
if (Json.contains("=on")) {
for (int i = 0; i < lijst.length; i++) {
if (lijst[i].contains("=on")) {
String[] getidstring=lijst[i].split("boolean");
int getidnum=parseInt(getidstring[1].substring(0,getidstring[1].indexOf("=")));
Optional<Product> optionalEntity = productRepository.findById(Long.valueOf(getidnum));
Product product = optionalEntity.get();
Orders order = new Orders();
String splitter=getidnum+"=";
String[] lijst2 = lijst[i].split(splitter);
int nummer = parseInt(lijst2[1].substring(0, 1));
order.setNumberOfProducts(nummer);
order.setCustomer(customersaved);
orderRepository.save(order);
var updateOrder = orderRepository.findById(order.getId());
Orders orderUpdated = updateOrder.get();
orderUpdated.setProduct(product);
orderRepository.save(orderUpdated);
}
}
return adres;
}
else
{
return "redirect:/";
}
}
else
{
return "redirect:/";
}
}
These are the entities Product, Customer and Order
Product:
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "products")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "productid")
private Long id;
#Column(name = "productname")
private String name;
#Column(name = "price")
private Double price;
#Column(name = "availability")
private boolean availability;
#Column(name = "photo")
private byte[] photo;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "product_category",
joinColumns = #JoinColumn(name = "productid"),
inverseJoinColumns = #JoinColumn(name = "categoryid"))
#JsonManagedReference
#JsonIgnore
private List<Category> category;
#OneToOne(mappedBy = "Product")
private Orders Order;
}
Customer:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "customers")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "customerid")
private Long id;
#Column(name = "firstname")
private String firstname ;
#Column(name = "lastname")
private String lastname ;
private String address;
#OneToMany(mappedBy = "customer")
private List<Orders> orders;
}
Order:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "Orders")
public class Orders {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "orderid")
private Long id;
#Column(name = "numberofproducts")
private int numberOfProducts;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="customerid")
private Customer customer;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
private Timeslot timeslot;
#OneToOne
#PrimaryKeyJoinColumn
private Product Product;
}
I have 3 tables as #Entity, and 2 join tables in my spring + hibernate app.
In one of join table i have extra column. I want to take info from this info column when i take info from my main table.
Main table code:
#Entity
#Table(name = "items")
public class Items {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "crafts"
,joinColumns = #JoinColumn(name = "item_id")
,inverseJoinColumns = #JoinColumn(name = "plot_id"))
private Set<Plots> plotInfo = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "item_materials"
,joinColumns = #JoinColumn(name = "item_id")
,inverseJoinColumns = #JoinColumn(name = "material_id"))
private Set<Materials> materialsInfo = new HashSet<>();
Table item_materials have this columns "id, item_id(fkey), material_id(fkey), expense" and one of this which names as "expense" i need to have in my final result.
How can i code my class to have "expense" in my result?
I read about #embeddable but still dont understand how to use in my project.
Don't use a #ManyToMany association. Map the join table as entity and model it similar to this:
#Entity
#Table(name = "items")
public class Items {
#OneToMany(mappedBy = "item")
private Set<Crafts> plotInfo = new HashSet<>();
}
#Entity
#Table(name = "plots")
public class Plots {
#OneToMany(mappedBy = "plot")
private Set<Crafts> items = new HashSet<>();
}
#Entity
#Table(name = "crafts")
public class Crafts {
#EmbeddedId
private CraftsId id;
#ManyToOne
#JoinColumn(name = "item_id", insertable = false, updatable = false)
private Items item;
#ManyToOne
#JoinColumn(name = "plot_id", insertable = false, updatable = false)
private Plots plot;
}
#Embeddable
public class CraftsId {
#Column(name = "item_id")
private Integer itemId;
#Column(name = "plot_id")
private Integer plotId;
// equals + hashCode
}
I have two tables:
ptUSER(userID, name)
ptProteinData(userID, total, goal)
I tried to implement this using Hibernate one to one relationship.
The implementation of those 2 tables are the following:
Implementation of ptUser table (User.java):
#Entity
#Table(name = "ptuser")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "userID", unique = true, nullable = false)
int userID;
#Column(name = "name", unique = true, nullable = false, length = 45)
String name;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "ptuser", cascade = CascadeType.ALL)
ProteinData proteinData;
// getters and setters
}
Implementation of ptProteinData table (ProteinData.java):
#Entity
#Table(name = "ptproteindata")
public class ProteinData {
#Id
#GeneratedValue(generator = "generator")
#GenericGenerator(name = "generator", strategy = "foreign", parameters = #Parameter(name = "property", value = "ptuser"))
int userID;
int total;
int goal;
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
User user;
//getter & setter
}
DAO layer implementation is like the following:
public class UserDAO {
public void addUserWithProteinData(String name, int goal, int total) {
Session session = HibernateUtilities.getSessionFactory().openSession();
session.beginTransaction();
User user = new User();
user.setName(name);
ProteinData proteinData = new ProteinData();
proteinData.setGoal(goal);
proteinData.setTotal(total);
user.setProteinData(proteinData);
proteinData.setUser(user);
session.saveOrUpdate(user);
session.getTransaction().commit();
session.close();
}
}
I tried to insert data using the following code:
UserDAO uDAO = new UserDAO();
uDAO.addUserWithProteinData("abc", 100, 10);
But I am unable to insert data using the above codes. Can you tell me where I am doing mistake. When I tried to execute this I am getting the following error:
Exception in thread "main"
java.lang.NullPointerException
at mydomain.UserDAO.addUserWithProteinData(UserDAO.java:43)
at mydomain.UserDAO.main(UserDAO.java:65)
Add the first line to your code, because you need to save proteinData first and then set in user object. Finally, you can save user.
session.saveOrUpdate(proteinData); // you need to save 'proteinData' first
user.setProteinData(proteinData);
proteinData.setUser(user);
session.saveOrUpdate(user);
Also amend these
// On User Class
#Entity
#Table(name = "ptuser")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "userID")
int userID;
#Column(name = "name", unique = true, nullable = false, length = 45)
String name;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "ptuser", cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
ProteinData proteinData;
}
// On ProteinData
#Entity
#Table(name = "ptproteindata")
public class ProteinData {
#Id
#GeneratedValue(generator = "generator")
#GenericGenerator(name = "generator", strategy = "foreign", parameters = #Parameter(name = "property", value = "ptuser"))
int userID;
int total;
int goal;
#OneToOne(fetch = FetchType.LAZY, mappedBy="ProteinData")
#PrimaryKeyJoinColumn
User user;
}
Add
(optional=false)
#JoinColumn(name="userID", unique=true, nullable=false, updatable=false)
What is the primary key of the second table ProteinData
I have student, test and student_test tables with many-to-many relationship.
Test:
#Entity
#Table(name = "TEST")
public class Test
{
#Id
#Column(name = "TEST_ID")
#GeneratedValue
private Long testId;
#Column(name = "SUBJECT")
private String subject;
#Column(name = "MAX_MARKS")
private String maxMarks;
#Column(name = "MARKS_OBTAINED")
private String marksObtained;
#Column(name = "RESULT")
private String result;
#ManyToMany(fetch = FetchType.LAZY,
mappedBy = "test",
cascade= {CascadeType.PERSIST})
private Set<Student> student = new HashSet<Student>();
}
Student:
#Entity
#Table(name = "STUDENT")
public class Student
{
#Id
#Column(name = "STUDENT_ID")
#GeneratedValue
private Long studentId;
#Column(name = "FIRSTNAME")
private String firstname;
#Column(name = "LASTNAME")
private String lastname;
#Column(name = "EMAIL")
private String email;
#Column(name = "PHONE")
private String phone;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(name = "STUDENT_TEST",
joinColumns = { #JoinColumn(name = "STUDENT_ID", updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "TEST_ID", updatable = false) })
private Set<Test> test = new HashSet<Test>();
}
I have created test record separately.
Now I wanted to insert a Student with relationship record.
The following code is trying to
update student record
update test record
insert a record in relationship table (student_test).
Test test1 = new Test();
test1.setTestId(Long.valueOf("3"));
student1.getTest().add(test1);
student1.setStudentId(Long.valueOf("1"));
try
{
session.saveOrUpdate(student1);
}
catch (HibernateException e)
{
e.printStackTrace();
}
session.getTransaction().commit();
session.close();`
My question is, I need to insert a record into Student and relationship table(student_test) only and it should not update record in test table.
I guess, you forgot to begin transaction. Add following line before saveUpdate
session.getTransaction().begin();
Every thing seems ok except your transaction management.. But I did not see the transaction open in your posted code but you have only transaction commit.. can you make the change and do test again ?
Cheers!