I am new to Hibernate, so please forgive me if the question is duplicated or stupid. I am using Hibernate 3.3.0, PostgreSQL DB. Right now I have 2 entities. I need to associate them with #OneToMany annotation in such way, that User.roleID was PK and Role.id was FK (user can have only one role, and the same role can be assigned to many users). Also as I was searching Google, I found out that for some reason every example with annotation associations has the annotated field declared as Set. Please, explain this to me. Thank you in advice.
Nazar.
User entity:
package com.dataart.mediaportal.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "users")
public class User implements Serializable {
private int id;
private String login;
private String password;
private String firstName;
private String lastName;
private int roleID;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id", unique = true)
public int getId() {
return id;
}
#Column(name = "user_login", nullable=false, unique = true, length = 20 )
public String getLogin() {
return login;
}
#Column(name = "user_password", nullable = false, length = 32)
public String getPassword() {
return password;
}
#Column(name = "user_name", nullable = true)
public String getFirstName() {
return firstName;
}
#Column(name = "user_lastname", nullable = true)
public String getLastName() {
return lastName;
}
#Column(name = "role_id", nullable = false)
public int getRoleID() {
return roleID;
}
public void setRoleID(int roleID) {
this.roleID = roleID;
}
public void setId(int id) {
this.id = id;
}
public void setLogin(String login) {
this.login = login;
}
public void setPassword(String password) {
this.password = password;
}
public void setFirstName(String firstname) {
this.firstName = firstname;
}
public void setLastName(String lastname) {
this.lastName = lastname;
}
}
Role entity:
package com.dataart.mediaportal.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "roles")
public class Role implements Serializable {
private int id;
private String role;
#Id
#Column(name = "role_id", nullable = false)
public int getId() {
return id;
}
#Column(name = "role_name", nullable = false)
public String getRole() {
return role;
}
public void setId(int id) {
this.id = id;
}
public void setRole(String role) {
this.role = role;
}
}
DB Script:
DROP TABLE IF EXISTS users CASCADE;
DROP TABLE IF EXISTS roles CASCADE;
DROP TABLE IF EXISTS albums CASCADE;
DROP TABLE IF EXISTS images CASCADE;
CREATE TABLE users
(
user_login character varying(20) NOT NULL,
user_password character varying(32) NOT NULL,
user_name character varying,
user_lastname character varying,
role_id integer DEFAULT 0,
user_id serial NOT NULL,
CONSTRAINT pk_user_id PRIMARY KEY (user_id),
CONSTRAINT users_user_login_key UNIQUE (user_login)
)
WITH (
OIDS=FALSE
);
ALTER TABLE users
OWNER TO postgres;
CREATE TABLE roles
(
role_id integer NOT NULL,
role_name character varying NOT NULL DEFAULT 'user'::character varying,
CONSTRAINT role_id_pk PRIMARY KEY (role_id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE roles
OWNER TO postgres;
INSERT INTO roles
VALUES ( 0, 'user' ),
( 1, 'admin' );
-- testlog - testpass
-- user - password
INSERT INTO users
VALUES ( 'testlog', '179ad45c6ce2cb97cf1029e212046e81', 'Nazar', 'Sobchuk', 1),
('user', '5f4dcc3b5aa765d61d8327deb882cf99', 'unknown', 'unknown', 0);
CREATE TABLE albums
(
album_name character varying NOT NULL,
user_id integer,
album_id serial NOT NULL,
CONSTRAINT album_id PRIMARY KEY (album_id),
CONSTRAINT user_id FOREIGN KEY (user_id)
REFERENCES users (user_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE albums
OWNER TO postgres;
CREATE INDEX fki_user_id
ON albums
USING btree
(user_id);
INSERT INTO albums VALUES ('Main Album', 1);
CREATE TABLE images
(
img bytea,
img_name character varying NOT NULL,
album_id integer,
img_id serial NOT NULL,
CONSTRAINT images_img_name UNIQUE(img_name),
CONSTRAINT album_id FOREIGN KEY (album_id)
REFERENCES albums (album_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE images
OWNER TO postgres;
CREATE INDEX fki_album_id
ON images
USING btree
(album_id);
Insert user:
public boolean insertUser(User user) {
factory = getSessionFactory();
session = factory.openSession();
tx = session.beginTransaction();
Query queryResult = session.createQuery("from User");
List<User> userList = queryResult.list();
for (User u : userList) {
if (u.getLogin().equalsIgnoreCase(user.getLogin())) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("User_is_already_registered"));
return false;
}
}
session.save(user);
tx.commit();
session.close();
return true;
}
Add the user as one to many relationship to Role as below. create the setters as well
private List<User> userList;
#OneToMany(mappedBy = "role")
public List<User> getUserList() {
return userList;
}
Add the Role as many to one relationship to User as below
private Role role;
#ManyToOne
public Role getRole() {
return role;
}
Related
I have 2 SQL tables:
Users:
CREATE TABLE users
(
id BIGINT PRIMARY KEY DEFAULT nextval('global_seq'),
/* email, password, other fields */
);
Users_avatars:
CREATE TABLE users_avatars
(
user_id BIGINT NOT NULL,
file_name VARCHAR,
file_path VARCHAR,
FOREIGN KEY (user_id) REFERENCES users (id)
);
However, why I try to map it with Hibernate it creates file_name and file_path inside the users table.
My classes are the following:
#Entity
#Table(name = "users")
#SecondaryTable(name = "users_avatars",
pkJoinColumns = #PrimaryKeyJoinColumn(name = "user_id", referencedColumnName = "id"))
public class User extends EntityWithId
{
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "file_name", column = #Column(table = "users_avatars")),
#AttributeOverride(name = "file_path", column = #Column(table = "users_avatars"))
})
private FileInDb avatar;
public FileInDb getAvatar()
{
return avatar;
}
public void setAvatar(FileInDb avatar)
{
this.avatar = avatar;
}
}
And FileInDb class:
#Embeddable
#MappedSuperclass
public abstract class FileInDb
{
#Column(name = "file_name")
#NotNull
#NotBlank
private String fileName;
#Column(name = "file_path")
#NotNull
#NotBlank
private String filePath;
public String getFileName()
{
return fileName;
}
public void setFileName(String fileName)
{
this.fileName = fileName;
}
public String getFilePath()
{
return filePath;
}
public void setFilePath(String filePath)
{
this.filePath = filePath;
}
}
SQL script generated by Hibernate:
create table users (
id int8 not null,
file_name varchar(255),
file_path varchar(255),
/* Lots of other fields */
primary key (id)
)
create table users_avatars (
user_id int8 not null,
primary key (user_id)
)
Why is so? Please help. Thanks in advance.
You can use #OneToOne mapping with #MapsId to use the user_id as the id field for the user_avatars table
Entity Class UserExtraDetails with having one to one relationship with APP_USER with column SSO_ID
package com.eportal.models;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "userdetails")
public class userExtraDetails implements Serializable {
#Column(name = "Address", nullable = true)
private String Address;
#Id
#Column(name = "SSO_ID", nullable = false)
private String ssoId;
#Column(name = "City", nullable = true)
private String City;
#Column(name = "Country", nullable = true)
private String Country;
#Column(name = "Postal_Code", nullable = true)
private String Postal_Code;
#Column(name = "about_me", nullable = true)
private String about_me;
#OneToOne(fetch = FetchType.LAZY)
#JoinTable(name = "APP_USER", joinColumns = { #JoinColumn(name = "SSO_ID") })
private User user;
public String getAbout_me() {
return about_me;
}
public String getSsoId() {
return ssoId;
}
public void setSsoId(String ssoId) {
this.ssoId = ssoId;
}
public void setAbout_me(String about_me) {
this.about_me = about_me;
}
public String getAddress() {
return Address;
}
public void setAddress(String address) {
Address = address;
}
public String getCity() {
return City;
}
public void setCity(String city) {
City = city;
}
public String getCountry() {
return Country;
}
public void setCountry(String country) {
Country = country;
}
public String getPostal_Code() {
return Postal_Code;
}
public void setPostal_Code(String postal_Code) {
Postal_Code = postal_Code;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Entity Class User with a one to one relationship with userdetails with column SSO_ID
package com.eportal.models;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.validator.constraints.NotEmpty;
#Entity
#Table(name = "APP_USER")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotEmpty
#Column(name = "SSO_ID", unique = true, nullable = false)
private String ssoId;
#NotEmpty
#Column(name = "PASSWORD", nullable = false)
private String password;
#NotEmpty
#Column(name = "FIRST_NAME", nullable = false)
private String firstName;
#NotEmpty
#Column(name = "LAST_NAME", nullable = false)
private String lastName;
#NotEmpty
#Column(name = "EMAIL", nullable = false)
private String email;
#OneToOne(fetch = FetchType.LAZY)
#JoinTable(name = "userdetails", joinColumns = { #JoinColumn(name = "SSO_ID") })
private userExtraDetails details;
#NotEmpty
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "APP_USER_USER_PROFILE", joinColumns = { #JoinColumn(name = "USER_ID") }, inverseJoinColumns = {
#JoinColumn(name = "USER_PROFILE_ID") })
private Set<UserProfile> userProfiles = new HashSet<UserProfile>();
public userExtraDetails getDetails() {
return details;
}
public void setDetails(userExtraDetails details) {
this.details = details;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSsoId() {
return ssoId;
}
public void setSsoId(String ssoId) {
this.ssoId = ssoId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<UserProfile> getUserProfiles() {
return userProfiles;
}
public void setUserProfiles(Set<UserProfile> userProfiles) {
this.userProfiles = userProfiles;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((ssoId == null) ? 0 : ssoId.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof User))
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (ssoId == null) {
if (other.ssoId != null)
return false;
} else if (!ssoId.equals(other.ssoId))
return false;
return true;
}
/*
* DO-NOT-INCLUDE passwords in toString function. It is done here just for
* convenience purpose.
*/
#Override
public String toString() {
return "User [id=" + id + ", ssoId=" + ssoId + ", password=" + password + ", firstName=" + firstName
+ ", lastName=" + lastName + ", email=" + email + "]";
}
}
18:31:55.434 [localhost-startStop-1] ERROR o.h.tool.hbm2ddl.SchemaUpdate - HHH000388: Unsuccessful: alter table APP_USER add constraint FK_1wjx4w75wu94ftp6jvt35krf0 foreign key (user_id) references APP_USER
18:31:55.434 [localhost-startStop-1] ERROR o.h.tool.hbm2ddl.SchemaUpdate - There is already an object named 'FK_1wjx4w75wu94ftp6jvt35krf0' in the database.
18:31:55.438 [localhost-startStop-1] ERROR o.h.tool.hbm2ddl.SchemaUpdate - HHH000388: Unsuccessful: alter table APP_USER add constraint FK_hqk6uc88j3imq8u9jhro36vt3 foreign key (SSO_ID) references userdetails
18:31:55.438 [localhost-startStop-1] ERROR o.h.tool.hbm2ddl.SchemaUpdate - The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_hqk6uc88j3imq8u9jhro36vt3". The conflict occurred in database "CloudDB", table "dbo.userdetails", column 'SSO_ID'.
18:31:55.440 [localhost-startStop-1] ERROR o.h.tool.hbm2ddl.SchemaUpdate - HHH000388: Unsuccessful: alter table APP_USER_USER_PROFILE add constraint FK_brmce0t584euix4wb4rursf1q foreign key (USER_ID) references APP_USER
18:31:55.440 [localhost-startStop-1] ERROR o.h.tool.hbm2ddl.SchemaUpdate - There is already an object named 'FK_brmce0t584euix4wb4rursf1q' in the database.
18:31:55.442 [localhost-startStop-1] ERROR o.h.tool.hbm2ddl.SchemaUpdate - HHH000388: Unsuccessful: alter table userdetails add constraint FK_pffebqmeoi5qdq5g63w450h1i foreign key (SSO_ID) references APP_USER
18:31:55.442 [localhost-startStop-1] ERROR o.h.tool.hbm2ddl.SchemaUpdate - Column 'APP_USER.id' is not the same data type as referencing column 'userdetails.SSO_ID' in foreign key 'FK_pffebqmeoi5qdq5g63w450h1i'.
18:31:55.442 [localhost-startStop-1] INFO o.h.tool.hbm2ddl.SchemaUpdate - HHH000232: Schema update complete
The following error is shown:
Unsuccessful: alter table APP_USER add constraint
FK_1wjx4w75wu94ftp6jvt35krf0 foreign key (user_id) references APP_USER
There is already an object named 'FK_1wjx4w75wu94ftp6jvt35krf0' in the
database.
Unsuccessful: alter table APP_USER add constraint
FK_hqk6uc88j3imq8u9jhro36vt3 foreign key (SSO_ID) references
userdetails
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint
"FK_hqk6uc88j3imq8u9jhro36vt3". The conflict occurred in database
"CloudDB", table "dbo.userdetails", column 'SSO_ID'.
Unsuccessful: alter table APP_USER_USER_PROFILE add constraint
FK_brmce0t584euix4wb4rursf1q foreign key (USER_ID) references APP_USER
There is already an object named 'FK_brmce0t584euix4wb4rursf1q' in the
database.
Unsuccessful: alter table userdetails add constraint
FK_pffebqmeoi5qdq5g63w450h1i foreign key (SSO_ID) references APP_USER
Column 'APP_USER.id' is not the same data type as referencing column
'userdetails.SSO_ID' in foreign key 'FK_pffebqmeoi5qdq5g63w450h1i'.
I have one parent object as Employee and child object as Address. I just need to update the both objects using Employee object. But when updating using employee object i just getting emp_id should not be null. Here is my table and entity
CREATE TABLE `employee` (
`employee_id` bigint(20) NOT NULL AUTO_INCREMENT,
`employee_name` varchar(30) NOT NULL,
`employee_desg` varchar(30) NOT NULL,
`salary` varchar(30) NOT NULL,
`employee_reference_id` varchar(10) NOT NULL,
PRIMARY KEY (`employee_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
Address table
CREATE TABLE `address` (
`address_id` bigint(20) NOT NULL AUTO_INCREMENT,
`emp_id` bigint(20) NOT NULL,
`address` varchar(255) NOT NULL,
PRIMARY KEY (`address_id`),
KEY `employee_address` (`emp_id`),
CONSTRAINT `employee_address` FOREIGN KEY (`emp_id`) REFERENCES `employee` (`employee_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
Employee Object
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "Employee")
public class Employee {
#Id
#GeneratedValue
#Column(name = "EMPLOYEE_ID")
private int id;
#Column(name = "EMPLOYEE_NAME")
private String employeeName;
#Column(name = "EMPLOYEE_DESG")
private String employeeDesg;
#Column(name = "SALARY")
private String salary;
#Column(name = "EMPLOYEE_REFERENCE_ID")
private String employeeReferenceId;
public String getEmployeeReferenceId() {
return employeeReferenceId;
}
public void setEmployeeReferenceId(String employeeReferenceId) {
this.employeeReferenceId = employeeReferenceId;
}
#OneToOne(mappedBy="employee", cascade = CascadeType.ALL)
private Address address;
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getEmployeeDesg() {
return employeeDesg;
}
public void setEmployeeDesg(String employeeDesg) {
this.employeeDesg = employeeDesg;
}
public String getSalary() {
return salary;
}
public void setSalary(String salary) {
this.salary = salary;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Address Object
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "ADDRESS")
public class Address {
#Id
#Column(name="ADDRESS_ID")
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name = "ADDRESS")
private String address;
#OneToOne(fetch=FetchType.EAGER , cascade=CascadeType.ALL, orphanRemoval=true)
#JoinColumn(name="emp_id",referencedColumnName="employee_id")
private Employee employee;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Address() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
My code is
public class StudentUtil1To1 {
public static void main(String args[]){
SessionFactory factory=null;
Configuration configuration=null;
ServiceRegistry registry=null;
Session session=null;
try{
configuration= new Configuration();
configuration.configure();
registry=new StandardServiceRegistryBuilder().configure().applySettings(configuration.getProperties()).build();
factory=configuration.configure("hibernate.cfg.xml").buildSessionFactory(registry);
session= factory.openSession();
session.beginTransaction();
Employee emp=new Employee();
emp.setId(1);
emp.setEmployeeReferenceId("CP001");
emp.setEmployeeName("Muthu");
emp.setEmployeeDesg("Developer");
emp.setSalary("15000");
Address address=new Address();
address.setAddress("3, Civil aerodrome, CBE");
emp.setAddress(address);
address.setEmployee(emp);
session.update(emp);
System.out.println("Successfuly Saved");
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
}finally{
if(session!=null){
session.close();
}
if(factory!=null){
factory.close();
}
}
}
}
And the error is
09:40:48.815 [http-nio-8081-exec-7] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 1048, SQLState: 23000
09:40:48.816 [http-nio-8081-exec-7] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - Column 'emp_id' cannot be null
What i need to for update. Correct my mistake.
Since you have already mapped Address entity in employee entity like this
#OneToOne(mappedBy="employee", cascade = CascadeType.ALL)
private Address address;
You dont have to do same thing in address class means
#OneToOne(fetch=FetchType.EAGER , cascade=CascadeType.ALL, orphanRemoval=true)
#JoinColumn(name="emp_id",referencedColumnName="employee_id")
private Employee employee;
Above code is not required in address entity.And remove the employee attribute from address class.
Now you already added the CascadeType.ALL in OneToOne annotation and save only employee object like this
Employee emp=new Employee();
Address address=new Address("your address");
emp.setAddress(address);
emp.setId(1);
emp.setEmployeeReferenceId("CP001");
emp.setEmployeeName("Muthu");
emp.setEmployeeDesg("Developer");
emp.setSalary("15000");
session.update(emp);
1.#MapppedBy annotation means:the entity annotationed by #MapppedBy,give up the reference of key,so in the employee table,dont have the column named "address_id".
the relation between Employee and Address controlled by "address" table.
2. when you use [session.update(emp);],you havent have the data of "Employee" table.but emp_id is the FOREIGN KEY,so will occur this problem
3. i can first insert Employee,then [session.update(emp);]
Hi write Spring application, using Spring Security. It's my database for user and account role:
create table users (
id int not null primary key,
username varchar2(20) not null unique,
password varchar2(20) not null,
firstName varchar2(20),
lastName varchar2(20),
personalId varchar2(11) unique,
city varchar2(40),
address varchar2(40),
email varchar2(30) unique,
phone varchar2(9) unique,
enabled number(1) not null
);
create table user_roles (
id int primary key,
name varchar2(20) not null,
username varchar(20) constraint username_fk references users(username) not null
);
My Entity classes:
#Entity
#Table(name = "users")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "id")
private Integer id;
#NotNull
#Column(name = "username")
private String username;
#NotNull
#Column(name = "password")
private String password;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#Column(name = "personalId")
private String personalId;
#Column(name = "city")
private String city;
#Column(name = "address")
private String address;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#NotNull
#Column(name = "enabled")
private int enabled;
#OneToMany(mappedBy = "username")
private Set<UserRole> userRoleSet = new HashSet<UserRole>(0);
#Entity
#Table(name = "user_roles")
public class UserRole implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "id")
private Integer id;
#NotNull
#Column(name = "name")
private String name;
#JoinColumn(name = "username")
#ManyToOne(targetEntity = User.class)
private String username;
When I try login in my system i have error:
Hibernate: select userrolese0_.username as username3_1_0_, userrolese0_.id as id1_0_0_, userrolese0_.id as id1_0_1_, userrolese0_.name as name2_0_1_, userrolese0_.username as username3_0_1_ from user_roles userrolese0_ where userrolese0_.username=?
WARN : org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1722, SQLState: 42000
ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ORA-01722: invalid number
My class implements UserDetailsService:
package pl.piotr.ibank.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pl.piotr.ibank.daointerface.UserDao;
import pl.piotr.ibank.model.UserRole;
#Transactional(readOnly = true)
#Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
#Autowired
UserDao userDao;
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
pl.piotr.ibank.model.User user = userDao.findByUsername(username);
List<GrantedAuthority> authorities = buildUserAuthority(user
.getUserRole());
return buildUserForAuthentication(user, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (UserRole userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getName()));
}
List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(
setAuths);
return result;
}
private UserDetails buildUserForAuthentication(
pl.piotr.ibank.model.User user, List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getPassword(), true, true,
true, true, authorities);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
I think so, my mapped foregin key for tables is bad. Example query from Userreturn users from table, but when i try get user_roles i have above error. Please check correctness my mapped. I using Oracle database and Hiberante.
The problem is, that when you're mapping entities Hibernate expects the foreign key to be the id of the referenced entity, i.e. you should map on user-id instead of username.
Also your entity mapping seems to be wrong: you use a ManyToOne with the target entity being User but the type of the property is String. AFAIK Hibernate would try to assign the user to username, which should fail miserably.
So the table should look like this:
create table user_roles (
id int primary key,
name varchar2(20) not null,
userid int constraint userid_fk references users(id) not null
);
And the mapping in UserRole should then be:
#JoinColumn(name = "userid")
#ManyToOne
private User user;
Plus the reverse mapping in User:
#OneToMany(mappedBy = "user")
private Set<UserRole> userRoleSet;
As a side note, please keep in mind that id is a special keyword in HQL, i.e. it will always reference an entity's id. If id always is the only property annotated with #Id then it's no problem, but if you change that you can run into problems with queries selecting the wrong data or even failing.
I have the following database structure:
CREATE TABLE `author` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `message` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(500) NOT NULL,
`text` varchar(50000) NOT NULL,
`author_id` int(10) unsigned DEFAULT NULL,
`creation_date` datetime NOT NULL,
`last_update_date` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `author_id_fk` (`author_id`),
CONSTRAINT `message_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`));
CREATE TABLE `comment` (
`id` int(10) unsigned NOT NULL,
`post_id` int(10) unsigned NOT NULL,
KEY `message_id_fk` (`id`),
KEY `post_id_fk` (`post_id`),
CONSTRAINT `comment_ibfk_1` FOREIGN KEY (`id`) REFERENCES `message` (`id`),
CONSTRAINT `comment_ibfk_2` FOREIGN KEY (`post_id`) REFERENCES `post` (`id`));
CREATE TABLE `post` (
`id` int(10) unsigned NOT NULL,
KEY `message_id_fk` (`id`),
CONSTRAINT `post_ibfk_1` FOREIGN KEY (`id`) REFERENCES `message` (`id`) ON DELETE CASCADE);
And the following mapping with hibernate(3.5.4-Final):
#Entity
#Table(name = "author")
public class Author {
private Long id = 0L;
private String name;
private String email;
private String password;
private Set<Post> posts;
private Set<Comment> comments;
#Id
#Column(name = "id")
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name = "password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#OneToMany(mappedBy = "author")
public Set<Post> getPosts() {
return posts;
}
public void setPosts(Set<Post> posts) {
this.posts = posts;
}
#OneToMany(mappedBy = "author")
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
#MappedSuperclass
#Table(name = "message")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Message implements Serializable {
private Long id;
private String title;
private String text;
private Author author;
private Date creationDate;
private Date lastUpdateDate;
#Id
#Column(name = "id")
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "title")
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Column(name = "text")
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#ManyToOne
#JoinColumn(name = "author_id")
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
#Column(name = "creation_date")
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
#Column(name = "last_update_date")
public Date getLastUpdateDate() {
return lastUpdateDate;
}
public void setLastUpdateDate(Date lastUpdateDate) {
this.lastUpdateDate = lastUpdateDate;
}
}
#Entity
#Table(name = "comment")
#PrimaryKeyJoinColumn(name="id")
public class Comment extends Message {
private static final long serialVersionUID = 1L;
private Post post;
#ManyToOne
#JoinColumn(name = "post_id")
public Post getPost() {
return post;
}
public void setPost(Post post) {
this.post = post;
}
}
#Entity
#Table(name = "post")
#PrimaryKeyJoinColumn(name="id")
public class Post extends Message {
private static final long serialVersionUID = 1L;
private Set<Comment> comments;
#OneToMany(mappedBy = "post")
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
The main idea is that Comment and Post are inherited from Message and I would like both of them to have bidirectional relation. But when I run the following code:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = session.beginTransaction();
Author author = new Author();
author.setName("mike");
author.setPassword("123");
author.setEmail("mike#gmail.com");
Post post = new Post();
post.setAuthor(author);
post.setCreationDate(new Date());
post.setLastUpdateDate(new Date());
post.setText("Text");
post.setTitle("Title");
Long authorId = (Long)session.save(author);
Long postId = (Long)session.save(post);
tx.commit();
I get the following error:
ERROR JDBCExceptionReporter:101 - Unknown column 'author_id' in 'field list'
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not insert: [org.blogsample.mappingbeans.Post]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)
Update
As #JB Nizet mentioned before I changed #MappedSuperclass to #Entity, after that I've got another error mappedBy reference an unknown target entity property: org.blogsample.mappingbeans.Comment.author, this was solved by changing db structure(removed author_id from message table, added it to each of comment, post and created foreign keys for this column) and moving author(and getter/setter with mapping) to Comment, Post classes.
Your Message class shouldn't be annotated with #MappedSuperclass, but with #Entity. #MappedSuperclass means that entities extending this class inherit columns and associations from the super class, but these columns and associations go in the table of the subclass. author_id is not in the comment table or in the post table. It's in the message table.
Moreover #Table can only be used with an entity. Not with a mapped superclass, which is only used to inherit fields and associations, but is not mapped to its own table like an entity is.
I think your issue here is exactly the same as the one highlighted in this question.
Have a look at my answer there to see if that helps.