JPA persisting twice - java

I'm trying to save into a MySQL database a entity that looks like this:
#Entity
#Table(catalog = "logistic", schema = "")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Movement.findAll", query = "SELECT m FROM Movement m"),
#NamedQuery(name = "Movement.findByIdMovement", query = "SELECT m FROM Movement m WHERE m.idMovement = :idMovement"),
#NamedQuery(name = "Movement.findByQty", query = "SELECT m FROM Movement m WHERE m.qty = :qty"),
#NamedQuery(name = "Movement.findByDt", query = "SELECT m FROM Movement m WHERE m.dt = :dt")})
public class Movement implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_movement", nullable = false)
private Long idMovement;
#Basic(optional = false)
#NotNull
#Column(nullable = false)
private int qty;
#Basic(optional = false)
#Column(nullable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date dt;
#JoinColumn(name = "from_id_container", referencedColumnName = "id_container", nullable = false)
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private Container fromIdContainer;
#JoinColumn(name = "to_id_container", referencedColumnName = "id_container", nullable = false)
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private Container toIdContainer;
#JoinColumn(name = "id_product", referencedColumnName = "id_product", nullable = false)
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private Product idProduct;
#JoinColumn(name = "username", referencedColumnName = "username", nullable = false)
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private User username;
// Getters and setters...
This entity has been generated by netbeans. The problem is that when I try to persist data into the database, it inserts two files instead of one. The code I use to persis the data is
Movement movement = new com.pccomponentes.sga.entity.Movement();
movement.setFromIdContainer(from);
movement.setToIdContainer(to);
movement.setIdProduct(product);
movement.setQty(obj.getInt("qty"));
movement.setUsername(userEJB.find(redis.get("token-" + token)));
movementEJB.create(movement);
What's happening?
Thank you in advance!

Related

Multiple queries executed by Hibernate with #OneToOne and #JoinColumnsOrFormulas

I have a table that contains personal data. This can be referenced by different tables.
PersonalData.java
#Entity
#Table(name = "personal_information")
#Getter
#Setter
public class PersonalInformation implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name = "personal_information_no")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "personal_information_seq")
#SequenceGenerator(name = "personal_information_seq", sequenceName = "personal_information_seq", allocationSize = 1, initialValue = 1)
private int personalInformationNo;
#Column(name = "ref_object_type")
private String refObjectType;
#Column(name = "ref_object_no")
private int refObjectNo;
#Column(name = "type")
private String type;
}
Staff.java
#Entity
#Table(name = "staff")
public class Staff {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "staff_no", unique = true, nullable = false)
private int staffNo;
#OneToOne(optional = false, fetch = FetchType.LAZY)
#LazyToOne(LazyToOneOption.NO_PROXY)
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(column = #JoinColumn( name = "staff_no", referencedColumnName = "ref_object_no", insertable=false, updatable=false)),
#JoinColumnOrFormula(formula = #JoinFormula( value = "(SELECT 'staff')", referencedColumnName = "ref_object_type")),
#JoinColumnOrFormula(formula = #JoinFormula( value = "(SELECT 'work')", referencedColumnName = "type"))
})
private PersonalInformation workPersonalInformation;
#OneToOne(optional = false, fetch = FetchType.LAZY)
#LazyToOne(LazyToOneOption.NO_PROXY)
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(column = #JoinColumn( name = "staff_no", referencedColumnName = "ref_object_no", insertable=false, updatable=false)),
#JoinColumnOrFormula(formula = #JoinFormula( value = "(SELECT 'staff')", referencedColumnName = "ref_object_type")),
#JoinColumnOrFormula(formula = #JoinFormula( value = "(SELECT 'private')", referencedColumnName = "type"))
})
private PersonalInformation privatePersonalInformation;
}
User.java
#Entity
#Table(name = "user")
public class BusinessProviderUser {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "user_no", unique = true, nullable = false)
private int userNo;
#Column(name = "staff_no")
private Integer staffNo;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(column = #JoinColumn( name = "user_no", referencedColumnName = "ref_object_no", insertable=false, updatable=false)),
#JoinColumnOrFormula(formula = #JoinFormula( value = "(SELECT 'user')", referencedColumnName = "ref_object_type"))
})
private PersonalInformation personalInformation;
}
As you can see, the reference is a bit more complex. This problem was solved with the annotation #JoinColumnsOrFormulas. The join to the person data is annotated #OneToOne in the referencing table.
The problem now is that each time the referencing table is called, additional queries are always executed.
How can I prevent this so that everything is executed in one query?
It is known that Hibernate does not support lazy loading with #OneToOne. One approach here was to implement lazy loading using bytecode enhencment. Unfortunately without success.
#OneToOne(fetch = FetchType.LAZY, optional = false)
#LazyToOne(LazyToOneOption.NO_PROXY)
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(column = #JoinColumn( name = "user_no", referencedColumnName = "ref_object_no", insertable=false, updatable=false)),
#JoinColumnOrFormula(formula = #JoinFormula( value = "(SELECT 'user')", referencedColumnName = "ref_object_type"))
})
private PersonalInformation personalInformation;
Another approach is to load everything in one single query by adding #Fetch(FetchMode.Join).
#OneToOne(optional = false)
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(column = #JoinColumn( name = "user_no", referencedColumnName = "ref_object_no", insertable=false, updatable=false)),
#JoinColumnOrFormula(formula = #JoinFormula( value = "(SELECT 'user')", referencedColumnName = "ref_object_type"))
})
#Fetch(FetchMode.JOIN)
private PersonalInformation personalInformation;
In the end, it is not crucial for the project whether the data is loaded lazy (preferred) or immediately.
It is only important that multiple queries are not sent per user or staff.
Are there any tips or solutions for the problem?
Maybe there is also a nicer solution regarding the database structure? Changes could be made here as well.
Unfortunately, Hibernate version 3.6.10-final must still be used.

multiple join in hibernate with criteria

i want to join 4 tables with hibernate. i write following code for fetch course name , teacher detail of course and schedules of course by student id:
my student entity is:
#Entity
#Table(name = "students", schema = "public")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "students_id_seq")
#SequenceGenerator(name = "students_id_seq", sequenceName = "students_id_seq", allocationSize = 1)
#Column(name = "id", nullable = false, unique = true)
private int id;
#Column(name = "name", nullable = false, length = 60)
private String name;
#Column(name = "code_melli", nullable = false, length = 10)
private String codeMelli;
#Column(name = "register_date", nullable = false)
private Date registerDate;
#Column(name = "mobile", length = 11)
private String mobile;
#Column(name = "phone", length = 15)
private String phone;
#Column(name = "email", length = 50)
private String email;
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "student_id", referencedColumnName = "id", insertable = false, updatable = false)
private List<Attend> attends;
my Attend Entity that determines the attendance of the student in the course and his score is:
#Entity
#Table(name = "attend", schema = "public")
public class Attend {
#EmbeddedId
AttendKey attendKey;
#Column(name = "score")
private int score;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "student_id", referencedColumnName = "id", insertable = false, updatable = false)
private Student student;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "course_id", referencedColumnName = "id", insertable = false, updatable = false)
private Course course;
course entity that map course detail is:
#Entity
#Table(name = "courses", schema = "public")
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "courses_id_seq")
#SequenceGenerator(name = "courses_id_seq", sequenceName = "courses_id_seq", allocationSize = 1)
#Column(name = "id", nullable = false, unique = true)
private int id;
#Column(name = "code")
private int code;
#Enumerated(EnumType.ORDINAL)
#Column(name = "cluster", nullable = false)
private ClusterType cluster;
#Column(name = "name", nullable = false, length = 40)
private String name;
#OneToOne
#JoinColumn(name = "teacher_id")
private Teacher teacher;
#Column(name = "students", nullable = false)
private int students;
#Column(name = "salary", nullable = false)
private int salary;
#Column(name = "tuition", nullable = false)
private int tuition;
#Column(name = "start_date")
private Date startDate;
#Column(name = "end_date")
private Date endDate;
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "course_id", referencedColumnName = "id", insertable = false, updatable = false)
private List<Schedule> scheduleList;
and schedule entity that saves the start and end time of the class in one day of the week is:
#Entity
#Table(name = "schedule", schema = "public")
#IdClass(ScheduleKey.class)
public class Schedule {
#Id
#Column(name = "course_id")
private int course_id;
#Id
#Column(name = "day")
#Enumerated(EnumType.ORDINAL)
private Day day;
#Column(name = "start", nullable = false)
private Time start;
#Column(name = "endt", nullable = false)
private Time endt;
how can i join these tables with hibernate criteria API and fetch course schedule of specific student.
SQL query for fetch data:
select
*
from
students
inner join
attend
on students.id=attend.student_id
inner join
courses
on attend.course_id=course.id
left outer join
schedule_
on course.id=schedule.course_id
left outer join
public.teachers
on course.teacher_id=teacher.id
where
students.id=102552
i use
public Student getStudentDetail(int studentId) {
Criteria criteria = createEntityCriteria();
criteria.add(Restrictions.eq("id", studentId));
criteria.setFetchMode("attends", FetchMode.JOIN);
Criteria attendCriteria = criteria.createCriteria("attends", "attend")
.setFetchMode("course", FetchMode.JOIN);
Criteria courseCriteria = attendCriteria.createCriteria("course", "course")
.setFetchMode("scheduleList", FetchMode.JOIN);
Criteria scheduleCriteria = courseCriteria.createCriteria("scheduleList", "schedule");
return (Student) scheduleCriteria.uniqueResult();
}

The abstract schema type 'User_Book' is unknown

I have a database with several entities, in particular Book and User. Between them there exists a ManyToMany relationship like this:
Book:
#Entity
#Table(name = "Books")
public class Book implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "bookId", nullable = false, unique = true)
private Long id;
#Column(name = "title", nullable = false)
private String title;
#Column(name = "price", nullable = false)
private int price;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "User_Book",
joinColumns = #JoinColumn(name = "bookId"),
inverseJoinColumns = #JoinColumn(name = "userId"))
private Set<UserAccount> users;
User:
#Entity
#Table(name = "UserAccounts")
public class UserAccount implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "userId", nullable = false, unique = true)
private Long id;
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
private String password;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "User_Book",
joinColumns = #JoinColumn(name = "userId"),
inverseJoinColumns = #JoinColumn(name = "bookId"))
Set<Book> purchasedBooks;
Everything works fine, the table User_Book is indeed created in the database. The problem seems to be related to the access of this Table.
For example,
Query query = entityManager.createQuery("SELECT u FROM User_Book u");
keeps telling me the following:
The abstract schema type 'User_Book' is unknown
So, shall I create from scratch the User_Book entity? Will it get automtically populated like now, that is, whenever a user buys a book, will this purchase be recorded in the table?
User_Book is not an entity. Therefore you cannot use createQuery, BUT you can use createNativeQuery to execute a SQL query:
Query query = entityManager.createNativeQuery("SELECT * FROM User_Book");
The result will be List<Object[]>

Can't write my SQL query in Spring Data JPA custom repository

There is part of SQL i want to realize in my Custom JPA repository
SELECT * FROM users u
JOIN skills_user sku on sku.user_id = u.id
JOIN specs_user spu on spu.user_id = u.id
GROUP BY u.id
HAVING ANY(sku.dictionary_id in (15,20) or spu.dictionary_id in (15,20))
ORDER BY u.id
I tried this:
//Other predicates
if (filterQuery.getSkills() != null && !filterQuery.getSkills().isEmpty()) {
String[] tmp = filterQuery.getSkills().replaceAll(" ", "").split(",");
List<Integer> ids = new ArrayList<>();
for (String s : tmp) {
ids.add(Integer.parseInt(s));
}
List<Predicate> tmpPredicates = new ArrayList<>();
Join<User, Dictionary> skillJoin = root.join("skillList");
Join<User, Dictionary> specsJoin = root.join("specsList");
for (Integer id : ids) {
tmpPredicates.add(builder.or(builder.equal(skillJoin.get("id"), id), builder.equal(specsJoin.get("id"), id)));
}
predicates.add(builder.and(tmpPredicates.toArray(new Predicate[tmpPredicates.size()])));
}
//Other predicates
But it isn't work correctly.
How can i realise this correctly in JPA custom repository?
there is code of User and Dictionary classes:
#Entity
#SequenceGenerator(name = "user_gen", sequenceName = "users_seq")
#Table(name = "users")
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_gen")
private Long id;
#Column(name = "login")
private String login;
#Column(name = "password")
private String password;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#Column(name = "middlename")
private String middlename;
#Column(name = "academic_group")
private String academicGroup;
#Column(name = "entrance_year")
private int entranceYear;
#Column(name = "avatar_URL")
private String avatarURL;
#Column(name = "salt")
private String salt;
#Enumerated(EnumType.ORDINAL)
#Column(name = "user_group")
private UserGroup group;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "SocialRole_User", joinColumns = {
#JoinColumn(name = "user_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "socialRole_id",
nullable = false, updatable = false) })
private List<SocialRole> socialRoleList;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "specs_user", joinColumns = {
#JoinColumn(name = "user_id", nullable = false, updatable = true)},
inverseJoinColumns = {#JoinColumn(name = "dictionary_id",
nullable = false, updatable = true)})
private List<Dictionary> specsList;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "skills_user", joinColumns = {
#JoinColumn(name = "user_id", nullable = false, updatable = true)},
inverseJoinColumns = {#JoinColumn(name = "dictionary_id",
nullable = false, updatable = true)})
private List<Dictionary> skillList;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Contacts> contactsList;
//Getters and setters
}
Dictionary:
#Entity
#SequenceGenerator(name = "dictionary_gen", sequenceName = "dictionary_seq")
#Table(name = "dictionary")
public class Dictionary {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "dictionary_gen")
private Long id;
#Column(name = "dic_name")
private String name;
#Enumerated(EnumType.STRING)
#Column(name = "dic_type")
private DictionaryType type;
// Getters and Setters
}
Have you tried writing the query using JPQL?
SELECT a FROM User a
INNER JOIN a.specsList b
INNER JOIN a.skillList c
GROUP BY a.id
HAVING ANY(b.id in (15,20) OR c.id in (15,20))
ORDER BY a.id;
This JPQL should work the same as your plain SQL.

Netbeans #JoinColoumns error with auto generated entity class

I've creating entities from a data-source using Netbeans 7.4.
And I have an error which arises with all entities which have a composite primary key. The error can be seen below.
I have searched this problem on stack-overflow and its is usually because people have not defined the join columns. but I have this done. I'm also unsure how there is errors in code generated by netbeans.
Here is an image of my MySQL database which I forward engineered to create these entitys:
Any help would be greatly appreciated !
Here is the only the relevant code
Absence entity:
public class Absence implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected AbsencePK absencePK;
#Basic(optional = false)
#NotNull
#Column(name = "idAbsence")
private int idAbsence;
#Basic(optional = false)
#NotNull
#Column(name = "Date")
#Temporal(TemporalType.DATE)
private Date date;
#Size(max = 35)
#Column(name = "type")
private String type;
#Lob
#Size(max = 65535)
#Column(name = "remark")
private String remark;
#JoinColumn(name = "TimeTable_Period", referencedColumnName = "Period", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Timetable timetable;
#JoinColumn(name = "Student_idStudent", referencedColumnName = "idStudent", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Student student;
#JoinColumn(name = "Class_idClass", referencedColumnName = "idClass", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Class class1;
AbsencePK entity:
#Embeddable
public class AbsencePK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "Class_idClass")
private int classidClass;
#Basic(optional = false)
#NotNull
#Column(name = "Student_idStudent")
private int studentidStudent;
#Basic(optional = false)
#NotNull
#Column(name = "TimeTable_Period")
private int timeTablePeriod;
public AbsencePK() {
}
public AbsencePK(int classidClass, int studentidStudent, int timeTablePeriod) {
this.classidClass = classidClass;
this.studentidStudent = studentidStudent;
this.timeTablePeriod = timeTablePeriod;
}
Error:
Caused by: Exception [EclipseLink-7220] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b):
org.eclipse.persistence.exceptions.ValidationException
Exception Description: The #JoinColumns on the annotated element [field timetable] from the entity class [class com.fyp.simstest.Absence] is incomplete.
When the source entity class uses a composite primary key, a #JoinColumn must be specified for each join column using the #JoinColumns.
Both the name and the referencedColumnName elements must be specified in each such #JoinColumn.
at org.eclipse.persistence.exceptions.ValidationException.incompleteJoinColumnsSpecified(ValidationException.java:1847)
EDIT
TimeTable
#Entity
#Table(name = "timetable")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Timetable.findAll", query = "SELECT t FROM Timetable t"),
#NamedQuery(name = "Timetable.findByPeriod", query = "SELECT t FROM Timetable t WHERE t.timetablePK.period = :period"),
#NamedQuery(name = "Timetable.findByDay", query = "SELECT t FROM Timetable t WHERE t.timetablePK.day = :day"),
#NamedQuery(name = "Timetable.findByClassidClass", query = "SELECT t FROM Timetable t WHERE t.timetablePK.classidClass = :classidClass")})
public class Timetable implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected TimetablePK timetablePK;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "timetable")
private Collection<Absence> absenceCollection;
#JoinColumn(name = "Class_idClass", referencedColumnName = "idClass", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Class class1;
public Timetable() {
}
public Timetable(TimetablePK timetablePK) {
this.timetablePK = timetablePK;
}
TimetablePK
Embeddable
public class TimetablePK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "Period")
private int period;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 45)
#Column(name = "Day")
private String day;
#Basic(optional = false)
#NotNull
#Column(name = "Class_idClass")
private int classidClass;
public TimetablePK() {
}
public TimetablePK(int period, String day, int classidClass) {
this.period = period;
this.day = day;
this.classidClass = classidClass;
}
EDIT TWO
Your diagram indicates the TimeTable table has a primary key composed of three columns (Period, Day, and Class_idClass). You will need to add an annotation to Absence.timeTable that looks something like this:
public class Absence implements Serializable {
...
#JoinColumns[
#JoinColumn(name = "TimeTable_Period", referencedColumnName = "Period", ...),
#JoinColumn(name = "????", referencedColumnName = "Day", ...),
#JoinColumn(name = "Class_idClass", referencedColumnName = "Class_idClass", ...)
]
#ManyToOne(optional = false)
private TimeTable timeTable;
...
}
Consider this:
#JoinColumn(name = "TimeTable_Period", referencedColumnName = "Period")
private Timetable timetable;
You have referenced to the column Period at your Timetable entity. But in the Timetable.java I don't see any field that is mapped with your Period column of your table.
For example:
#Id // as its the primary key!
#Column(name="Period")
private Long period
This should be same for other referenced entities those you have used with your #ManyToOne mapping.

Categories

Resources