I am using hibernate 3 and attempting to delete a record in the database, and the delete is not working as I would expect. The schema hibernate is working against (in pseudocode):
create table Employer(
employer_id number(12) primary key,
employer_name varchar2(50)
);
create table Employee(
employee_id number(12) primary key,
employee_name varchar2(50),
employer_id number(12) foreign key references employer.employer_id not null
);
create table Employee_Roles(
role_id number(12) primary key,
employee_id number(12) foreign key references employee.employee_id not null,
role varchar2(50)
);
My hibernate class mappings look something like:
#Entity
public class Employer{
#Id
#Column(name = "EMPLOYER_ID")
private long id;
#Column
private String name;
#OneToMany(targetEntity = Employee.class, fetch = FetchType.EAGER)
#JoinColumn(name = "employer_id")
#Cascade(CascadeType.ALL)
private Set<Employee> employees;
}
#Entity
public class Employee{
#ManyToOne(targetEntity = Employer.class)
#JoinColumn(name = "employer_id")
#Cascade(value = CascadeType.SAVE_UPDATE)
private Employer employer;
#OneToMany(targetEntity = EmployeeRole.class, fetch = FetchType.EAGER)
#JoinColumn(name = "employee_id")
#Cascade(CascadeType.ALL)
private Set<Employee> employees;
}
#Entity
public class EmployeeRole{
#ManyToOne(targetEntity = Employee.class)
#JoinColumn(name = "employee_id")
#Cascade(value = CascadeType.SAVE_UPDATE)
private Employee employee;
}
Now with this configuration I am calling:
getCurrentSession().delete(someEmployerEntity);
What is occurring is:
Hibernate: update EMPLOYEE set EMPLOYEE_ID=null where EMPLOYEE_ID=?
Hibernate: update EMPLOYEE_ROLE set employee_id=null where employee_id==?
[2011-04-15 15:59:53,487] JDBCExceptionReporter WARN - SQL Error: -10, SQLState: 23502
[2011-04-15 15:59:53,487] JDBCExceptionReporter ERROR - integrity constraint violation: NOT NULL check constraint; SYS_CT_10058 table: EMPLOYEE_ROLE
and an exception being raised. What I am expecting as a result of the session.remove(..) call is the employer record to be deleted, as well as all employee records associated with the employer and all EmployeeRole records associated with the deleted employee records. Is this a correct assumption? Or am I misunderstanding a key concept here?
Cascade all-delete-orphan should solve your problem. However, it is part of Hibernate and not EJB standard. If you want to do it and do not be trapped in your vendors' solution, I would suggest you to have a look to this article.
Good luck!
EDIT: following your suggestions I added the 'mappedBy' attributes to the #OneToMany annotations which seems to be the annotations way of using inverse="true" for specifying the owning relationships. The relevant changed sections of the relationships look like:
public class Employee{
#OneToMany(targetEntity = EmployeeRole.class, mappedBy="employee", fetch = FetchType.EAGER, cascadeType=CascadeType.ALL)
private Set<EmployeeRole> employeeRoles;
}
public class Employer{
#OneToMany(targetEntity = Employee.class, mappedBy="employer", fetch = FetchType.EAGER, cascadeType=CascadeType.ALL)
private Set<Employee> employees;
}
Related
in spring boot i want to achieve that if i can access employee table from employee_personal_detail table and also i can access
employee_persona_detail table from employee vice-versa while adding
data Why Foreign key not inserted in hibernate
so not able to access employee from access employee_persona_detail
employee table
#OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL,mappedBy = "employee")
public EmployeePersonalDetail employeePersonalDetail;
#Table(name="employee_personal_details")
#ToString
public class EmployeePersonalDetail {
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employee_id")
private Employee employee;
}
I have 3 entity classes like below:-
Role Entity
#Entity
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany
#LazyCollection(LazyCollectionOption.FALSE)
#JoinTable(name = "roles_privileges", joinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "privilege_id", referencedColumnName = "id"))
private Set<Privilege> privileges;
// getters, setters etc
}
Privilege Entity
#Entity
public class Privilege {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToMany(mappedBy = "privileges", fetch = FetchType.EAGER)
#JsonIgnore
private Set<Role> roles;
// getters, setters etc
}
UrlsMapper Entity
#Entity(name = "urls_mapper")
#Table(name = "urls_mapper")
public class UrlsMapper {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Enumerated(EnumType.STRING)
#Column(name = "http_method")
private HttpMethod httpMethod;
#Column(name = "path")
private String path;
#ManyToMany(fetch = FetchType.EAGER)
#MapKeyJoinColumn(name = "role_id", referencedColumnName = "id")
#JoinTable(
name = "u_r_p",
inverseJoinColumns = #JoinColumn(name = "privilege_id")
)
Map<Role, Privilege> privilegeMap;
// getters, setters etc
}
The keys, primary and foreign that get created are as below
The logs while table generation is as below:-
Hibernate: create table u_r_p (urls_mapper_id bigint not null, privilege_id bigint not null, role_id bigint not null, primary key (urls_mapper_id, role_id)) engine=InnoDB
Hibernate: alter table u_r_p add constraint FKgd7gd9f9ded1s28swdudqs0ro foreign key (privilege_id) references Privilege (id)
Hibernate: alter table u_r_p add constraint FKrryprkx4j60lyjti16eysn5g5 foreign key (role_id) references Role (id)
Hibernate: alter table u_r_p add constraint FKfkthdnoca59a18ba96183p7ov foreign key (urls_mapper_id) references urls_mapper (id)
And I just want to know how can I add the privilege_id also into the JoinTable u_r_p and if there can be other best options for this. Manually doing in the database is a obvious alternate, but i wanted to know the hbm2ddl.auto based solution, so that code manages it itself
I don't think you've modeled your concepts properly. You have a ManyToMany between Role and Priviledge but what makes UrlMapper an entity? You have a Map<Role, Privilege> field in UrlMapper but that is the purpose of the join table so there should be no need to duplicate that. Instead it seems to be that HttpMethod and Path are attributes of the relationship.
However, I might also note that you seem to be expecting there be a Role/Privilege join for many different HttpMethod/Path combinations. This seems incredibly fine grained and an operations nightmare, but whatever. Anyway, what you seem to be saying is you want unique combinations of Role/Privilege/HttpMethod/Path so you should just make a entity for that and the table represents your set. Make a Permission entity that holds a unique Role/Privilege/HttpMethod/Path. Role, Privilege, HttpMethod, and even Path are essentially enumerations so you should have a table for each for each of them with ManyToOne mappings in the Permission entity. You could add bidirectional OneToMany mappings in each of the lookup tables but I'm not sure I see a need for that. It's up to you.
I assume Privilege would be {allow, deny} but it seems like less of a tangle if you assume deny unless a Role/HttpMethod/Path permission specifically exists. If that's the case then I would leave out the Privilege entity. Anyway, just a thought. Hope this helps.
Hibernate crashes when using more than one #OneToMany entries in my Users.entity and I don't understand why.
I have a table for users (primary key userID) and various other tables which refer to the primary key userID by a foreign key set in database (InnoDB set and foreign key is set in each depending table).
Here an example with three tables:
Table users:
CREATE TABLE `users` (`userID` int(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `users` ADD PRIMARY KEY (`userID`);
Table: vacationrequests
CREATE TABLE `vacationrequests` (`requestID` int(11) NOT NULL,`userID` int(4) NOT NULL,) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `vacationrequests` ADD CONSTRAINT `userID` FOREIGN KEY (`userID`) REFERENCES `users` (`userID`) ON UPDATE CASCADE; COMMIT;
Table monthend:
CREATE TABLE `monthend` (`monthendID` int(11) NOT NULL,`userID` int(4) NOT NULL,) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Entity Users:
#Entity
#Table(name="users")
public class Users {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="userID")
private int userID;
... .... (other variables)
#OneToMany(fetch = FetchType.LAZY, mappedBy="monthend")
private Set<Monthend> monthend;
#OneToMany(fetch = FetchType.LAZY, mappedBy="vacationrequests")
private Set<Vacationrequests> vacationrequests;
public Users() {
}
Entity Vacationrequests:
#Entity
#Table(name="vacationrequests")
public class Vacationrequests {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="requestID")
private int requestID;
... .... (other variables)
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="userID", nullable = false)
private Users users;
public Vacationrequests() {
}
Entity Monthend:
#Entity
#Table(name="monthend")
public class Monthend {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="monthendID")
private int monthendID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="userID", nullable = false)
private Users users;
#Column(name="clientID")
private int clientID;
#Column(name="month")
private int month;
#Column(name="year")
private int year;
#Column(name="monthend")
private int monthend;
public Monthend() {
}
Working Query:
List<Object> listJoinUsersMonthend = session.createQuery("from Monthend m inner join m.users as users where m.clientID = :clientID AND m.year = :year AND users.loginclass = 0 AND users.isactive = 1 AND m.monthend = 0 AND m.month < :month order by users.userID asc")
.setInteger("clientID", user.getClientID())
.setInteger("year", year)
.setInteger("month", month)
.getResultList();
This second query i would like to integrate:
List<Object> listJoinVacationrequestsUsers = session.createQuery("from Vacationrequests v inner join v.users as users where v.clientID = :clientID AND v.approved=0 AND v.vacationtype=1 AND YEAR(v.startdate) = :year" )
.setInteger("clientID", user.getClientID())
.setInteger("year", year)
.getResultList();
Everything works fine with just one query and one entry in the Users.entity. As soon as I add the two entries hibernate just crashes and there is no error message. Is it not possible to do two #OneToMany statements in a entity ?
It seems that the problem is in the mapping of the associations in the Users entity.
You should change the mappedBy attribute of the associations to specify the field name that references the current entity in the associated one (in this case users), like this:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "users")
private Set<Monthend> monthend;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "users")
private Set<Vacationrequests> vacationrequests;
I have a relation between Accommodation and Booking classes, and also I set a foreign key in booking table.
ALTER TABLE `project`.`booking`
ADD INDEX `fk_accId_fk_idx` (`accommodation` ASC);
ALTER TABLE `project`.`booking`
ADD CONSTRAINT `fk_accId_fk`
FOREIGN KEY (`accommodation`)
REFERENCES `project`.`accommodation` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
Accommodation class:
#Entity
....
public class Accommodation implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private BigInteger id;
#OneToMany(mappedBy = "accommodation", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
#JsonManagedReference
private List < Booking > bookings;
......getters setters
}
Booking class:
#Entity
public class Booking implements Serializable {
......
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "bookings", nullable = true)
#JsonBackReference
private Accommodation accommodation;
....getters setters
}
When I execute a query for listing accommodations, I get unknown column in field list error.
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'bookings7_.bookings' in 'field list'
Even I set the relation and define the foreign key in table, what is the reason that I get this error?
Try to define your join-table mapping manually in JPA. Drop your schema and let JPA create your tables:
Accommodation class
#OneToMany(mappedBy = "accommodation", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
#JsonManagedReference
private List < Booking > bookings;
Booking class
#ManyToOne(fetch = FetchType.EAGER)
#JoinTable(name = "accommodation_booking_join_table",
joinColumns = {#JoinColumn(name="booking_id")},
inverseJoinColumns = #JoinColumn(name = "accommodation_id"))
#JsonBackReference
private Accommodation accommodation;
Try changing your column names to lower case in your db and entity class.
I had a situation like that, and I solved it by changing the field's position on the query. Looks like it's a MySQL bug, like (or the same as) the one mentioned on this post:
https://bugs.mysql.com/bug.php?id=1689
The description of this MySQL bug mentioned a similar workaround solution: "I found that by swapping that field's position in the table with another field that it worked OK."
I am learning hibernate and stuck a bit with the below problem
have two tables
CREATE TABLE department (
department_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
caption varchar(255) DEFAULT NULL) ENGINE=InnoDB;
CREATE TABLE employee (
employee_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
fio varchar(255) DEFAULT NULL,
fk_department_id int(11) NOT NULL,
FOREIGN KEY (fk_department_id) REFERENCES department (department_id)
) ENGINE=InnoDB ;
and two classes (in the first class commented out code looks like working solution)
#Entity
#Table(name = "department")
public class Department {
....
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "employee", joinColumns = {
#JoinColumn(name = "fk_department_id", referencedColumnName = "department_id") })
/*
* #OneToMany(fetch = FetchType.LAZY, mappedBy = "department", cascade =
* CascadeType.ALL)
*/
public Set<Employee> getEmployies() {
return employees;
}
#Entity
#Table(name = "employee")
public class Employee {
......
#ManyToOne
#JoinColumn(name = "fk_department_id")
public Department getDepartment() {
return department;
}
this results into
INFO: HHH000423: Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4
Exception in thread "main" org.hibernate.MappingException: Foreign key (FK3cspe1b06hmsik5l8y1i11xmd:employee [employies_employee_id])) must have same number of columns as the referenced primary key (employee [fk_department_id,employies_employee_id])
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:148)
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:130)
Please help me to understand why this doesn't work
The following should work just fine. You'll notice I am not specifying any join column relations because I am allowing Hibernate to generate those automatically for me.
#Entity
public class Department {
#OneToMany
#JoinTable(name = "department_employees")
private List<Employee> employees;
}
#Entity
public class Employee {
#ManyToOne
private Department department;
}
But lets assume you want to be explicit about the join columns.
#Entity
public class Department {
#Id
#Column(name = "department_id")
private Integer id;
#OneToMany
#JoinTable(
name = "department_employees",
joinColumns = #JoinColumn(name = "department_id"),
inverseJoinColumns = #JoinColumn(name = "employee_id"))
private List<Employee> employees;
}
#Entity
public class Employee {
#Id
#Column(name = "employee_id")
private Integer id;
#ManyToOne
#JoinTable(
name = "department_employees",
joinColumns = #JoinColumn(name = "department_id", insertable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "employee_id", insertable = false, updatable = false))
private Department department;
}
The key points to take away from this are:
The name of the join table specifies the middle table that maintains the relationship between the Department and Employee entities. It should not refer to the Employee table as your code illustrates.
The joinColumns attribute represents the primary key attributes of the containing entity, in this case that is Department, hence I used department_id.
The inverseColumns attribute represents the primary key attributes of the associated entity, in this case that is Employee, hence I used employee_id.
Update:
If you'd like to eliminate the #JoinTable and merely maintain the relationship between Department and Employee, you'd change your mappings as follows:
#Entity
public class Department {
#OneToMany(mappedBy = "department")
private List<Employee> employees;
}
#Entity
public class Employee {
#ManyToOne
private Department department;
}
Hope that helps.