I have two tables:
CREATE TABLE users
(
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(68) NOT NULL,
oldPassword VARCHAR(68),
enabled BOOLEAN NOT NULL
);
and
CREATE TABLE authorities (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL,
FOREIGN KEY (username) REFERENCES users(username)
);
CREATE UNIQUE INDEX ix_auth_username on authorities (username,authority);
Unfortunatelly instead of joining with authority_id which should be in users table I just have username which is the same in both tables.
In models I tried (ommited getters and setters):
#Entity(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
private String oldPassword;
private boolean enabled;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "username", referencedColumnName = "username")
private Authorities authority;
}
and
#Entity
public class Authorities {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String authority;
#OneToOne(mappedBy = "authority")
private User user;
}
but then I have an error: Repeated column in mapping for entity column: username (should be mapped with insert="false" update="false")
The reason you are getting usernames in both tables is that you have declared username column in both the tables.
Also, you have to map the relation based on the authority_id so the code of the models would look like this:
#Entity(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
private String oldPassword;
private boolean enabled;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "authority_id", referencedColumnName = "id")
private Authorities authority;
}
#Entity
public class Authorities {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String authority;
#OneToOne(mappedBy = "authority")
private User user;
}
And the tables will be created like this:
Hope this solves your problem.
The message is clear: you have a repeated column in the mapping, and a column "username" in both tables has repeated. Instead of this, you should use this :
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "authority_username", referencedColumnName = "username")
private Authorities authority;
Related
i have a BD on PostgreSQL and i have many tables, but my problem is at table Usuario.
I create the table with this script:
CREATE SEQUENCE usuario_id_seq;
CREATE TABLE public.usuario
(
id BIGINT NOT NULL DEFAULT nextval ('usuario_id_seq'::regclass),
administrador BOOLEAN NULL,
password CHARACTER VARYING (20) NOT NULL,
username CHARACTER VARYING (40) NOT NULL,
CONSTRAINT usuario_pkey PRIMARY KEY (id)
NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT uk_863n1y3x0jalatoir4325ehal UNIQUE (username)
NOT DEFERRABLE INITIALLY IMMEDIATE
);
And I insert one user with:
Insert into usuario (username, password, administrador) values ('prueba', '1234', false);
This goes ok, now i have on Spring-boot this:
#Entity
#Table(name = "usuario")
public class Usuario implements Serializable {
#Id
#GeneratedValue
private Long id;
#NotNull
#Size(max = 40)
#Column(name = "username", unique = true)
private String username;
#NotNull
#Size(max = 20)
#Column(name = "password")
private String password;
#Column(name = "administrador")
private boolean administrador;
#ManyToMany(cascade = {
CascadeType.ALL
})
#JoinTable(name = "usuario_alerta",
joinColumns = {#JoinColumn(name = "id_usuario", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "id_alerta", referencedColumnName = "id")})
private Set<Alerta> alertasUsuario;
#ManyToMany(cascade = {
CascadeType.ALL
})
#JoinTable(name = "usuario_producto",
joinColumns = {#JoinColumn(name = "id_usuario", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "id_producto", referencedColumnName = "id")})
private Set<Producto> productosUsuario;
// Hibernate requires a no-arg constructor
public Usuario() {
}
public Usuario(String username, String password, boolean administrador) {
this.username = username;
this.password = password;
this.administrador = administrador;
}
..... Getters and Setters
Now, when i try to insert into table Usuario using API, calling to this:
#PostMapping("/usuario")
ResponseEntity<Usuario> newUser(#ModelAttribute Usuario usuario) {
Usuario user = usuarioRepository.save(usuario);
if(user != null)
return new ResponseEntity<Usuario>(user, HttpStatus.CREATED);
return new ResponseEntity<Usuario>(user, HttpStatus.BAD_REQUEST);
}
I get the error:
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "usuario_pkey" Detail: Key (id)=(1) already exists.
And this is because i create the user with id=1 ont the init script.
Who can i insert into a table using SQL and after using Spring-boot without get this error?
Ok, i saw that #GeneratedValue has a atribute generator so I just try to add the sequence generator that i had created before and it works. So, the solution was put this line like:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY, generator="usuario_id_seq")
private Long id;
I am developing a spring boot application, i need a proper design help for one of my entity relation.
These are my tables
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
User_ID INT AUTO_INCREMENT PRIMARY KEY,
Email VARCHAR(1024),
Phone BIGINT,
Password VARCHAR(128),
User_Type ENUM ('TEACHER', 'PARENT'),
Status ENUM ('ACTIVE', 'DEACTIVE', 'SUSPENDED')
);
DROP TABLE IF EXISTS teacher;
CREATE TABLE teacher
(
Teacher_ID INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(1024),
Email VARCHAR(1024),
Phone BIGINT,
Gender ENUM (0, 1),
Date_Of_Joining INT,
Designation VARCHAR(1024),
Is_Active INT
);
DROP TABLE IF EXISTS parent;
CREATE TABLE parent
(
Parent_ID INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(1024),
Email VARCHAR(1024),
Phone BIGINT,
Occupation VARCHAR(1024),
Address VARCHAR(4048)
);
DROP TABLE IF EXISTS student;
CREATE TABLE student
(
Student_ID INT AUTO_INCREMENT PRIMARY KEY,
Student_Name VARCHAR(1024),
Class VARCHAR(16),
Section VARCHAR(16),
Academic_Year VARCHAR(64),
DOB DATE,
Gender ENUM (0, 1),
Parent_ID INT
);
Can anyone please help me creating entity classes for the same. Based on the type of user in user table i need to join with either teacher or parent table. For example if User_Type is TEACHER then i will join with teacher table else i will join user with parent table. Join condition would be email.
Student table has one to one relationship with parent table.
You can create domain models like this
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
public User{
//properties
}
#Entity
#PrimaryKeyJoinColumn(name = "id")
public Teacher extends User{
//properties
}
#Entity
public Parent extends User{
//properties
}
#Entity
public Students {
#GenericGenerator(name = "generator", strategy = "foreign",parameters = #Parameter(name = "property", value = "stock"))
#Id
#GeneratedValue(generator = "generator")
#Column(name = "Parent_ID", unique = true, nullable = false)
private Integer id;
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
public Parent parent;
}
You can use the following classes:
User:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
#Table(name = "user")
public class User {
#Id
#GeneratedValue
#Column(name = "User_ID")
private Integer userID;
#Column(name = "name", length = 1024)
private String name;
#Column(name = "email", length = 1024)
private String email;
#Column(name = "Phone")
private Long phone;
#Column(name = "Password", length = 128)
private String password;
#Column(name = "User_Type", columnDefinition = "enum ('TEACHER', 'PARENT')")
private String userType;
#Column(name = "Status", columnDefinition = "enum ('ACTIVE', 'DEACTIVE', 'SUSPENDED')")
private String status;
}
Teacher:
#Entity
#Table(name = "teacher")
public class Teacher extends User{
#Id
#GeneratedValue
#Column(name = "teacher_ID")
private Integer teacherID;
#Column(name = "name", length = 1024)
private String name;
#Column(name = "email", length = 1024)
private String email;
#Column(name = "Phone")
private Long phone;
#Column(name = "Gender", columnDefinition = "BOOLEAN")
private Boolean gender;
#Column(name = "Date_Of_Joining")
private Integer dateOfJoining;
#Column(name = "Designation", length = 1024)
private String designation;
#Column(name = "Is_Active")
private Integer isActive;
}
Parent:
#Entity
#Table(name = "parent")
public class Parent extends User{
#Id
#GeneratedValue
#Column(name = "Parent_ID")
private Integer parentID;
#Column(name = "name", length = 1024)
private String name;
#Column(name = "email", length = 1024)
private String email;
#Column(name = "Phone")
private Long phone;
#Column(name = "Occupation", length = 1024)
private String occupation;
#Column(name = "Address",length=4048)
private String address;
}
Student:
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue
#Column(name = "Student_ID")
private Integer studentID;
#Column(name = "student_name", length = 1024)
private String studentName;
#Column(name = "study_class", length = 16)
private String studyClass;
#Column(name = "section", length = 16)
private String section;
#Column(name = "academic_year",length = 64)
private String academicYear;
#Temporal(TemporalType.DATE)
#Column(name = "dob", length = 4048)
private Date dob;
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn(name = "parent")
public Parent parent;
}
Try them out and see if that helps.
I have User and Role classes with ManyToMany relationship. When I'm adding Role object to List roles in User object the 'user_roles' table columns 'username' and 'role_name' gets populated with User and Role objects primary keys' which are their ids. I wanted to know whether its possible to reference not primary keys(ids) and get username and Role.name in those columns instead?
#Entity
#Table(name = "users")
#SecondaryTable(name = "user_info", pkJoinColumns = {
#PrimaryKeyJoinColumn(name = "info_id", referencedColumnName = "user_id") })
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#ManyToMany
#JoinTable(name="user_roles",
joinColumns= {#JoinColumn(name="username"/*, referencedColumnName="username"*/)},
inverseJoinColumns= {#JoinColumn( name="role_name"/*, referencedColumnName="role_name"*/)}
)
private List<Role> roles;
#Entity
#Table(name = "roles")
public class Role {
#Id
#Column(name = "role_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "role_name")
private String name;
#ManyToMany
private List<User> users;
Also if I remove the comments around referencedColumnName I get error when trying to fetch all users from the database. I haven't added any data to database so even when querying empty database I'm getting this error:
Caused by: org.hibernate.HibernateException: Found shared references
to a collection: com.recipee.model.User.roles
The reason I'm using such database schema is because I'm trying to use Tomcat realm authentication where I need username and role_name in one database table.
we are having a slight issue with our application
we are trying to get a login page set up and run with glassfish so that can do the authentication, in our test application we could do this but we used tables :
create table person(
username varchar(128) NOT NULL CONSTRAINT USER_PK PRIMARY KEY ,
password varchar(128) NOT NULL
..... many more fields here but are just for dob etc
);
and
create table usergroup(
username varchar(128) NOT NULL,
groupname varchar(128) NOT NULL,
CONSTRAINT GROUP_PK PRIMARY KEY(username, groupname),
CONSTRAINT USER_FK FOREIGN KEY(username) REFERENCES person(username)
ON DELETE CASCADE ON UPDATE RESTRICT
);
this worked well but for this application we are trying to get the entities to manage everything and create the tables, the issue we are having is with the constraints we set up, how can we set this up in the entites ?
The person entities
#Entity
public class Person implements Serializable {
#ManyToOne
private Address address;
#OneToMany
private List<UserGroup> userGroupList;
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName, surname, username, password, telephoneNumber, emailAddress,gender;
#Temporal(TemporalType.DATE)
private Date DateOfBirth;
public Person() {
}
public void addToGroups(UserGroup ug) {
this.userGroupList.add(ug);
}
and the usergroup entity
#Entity
public class UserGroup implements Serializable {
private static final long serialVersionUID = 1L;
#JoinColumn(name = "USERNAME", referencedColumnName = "USERNAME", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Person person;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username, groupName;
we need the constraints and settings as with out these are we not able to authenticate correctly using glassfish
Consider the following database schema:
create table UserGroup ( id int not null auto_increment, name varchar(200),
primary key(id));
create table User ( id int not null auto_increment, name varchar(200),
groupId int not null, primary key(id));
User.groupId = UserGroup.id, so a user can only be a member of one group, but a usergroup can exist of many users. Fine so far, let's make the entities in Hibernate. Here's User:
#Entity
#Table(name = "User")
public class User {
#Id
#Column(name="id", nullable = false)
private Integer id;
#Column(name="name", length = 200, nullable = true)
private String name;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "groupId", nullable = false, insertable=false, updatable=false)
#ForeignKey(name="FK_GroupId")
private UserGroup userGroup;
/* Getters, Setters, toString, equals & hashCode */
}
Here's UserGroup:
#Entity
#Table(name = "UserGroup")
public class UserGroup {
#Id
#Column(name="id", nullable = false)
private Integer id;
#Column(name="name", length = 200, nullable = true)
private String name;
#OneToMany(fetch=FetchType.EAGER)
private List<User> users;
/* Getters, Setters, toString, equals & hashCode */
}
Now I'll get an error "Table mydb.usergroup_user' doesn't exist" because it expects a join-table. My data structure is "set in stone" due to interoperability with other applications that this application will replace, so I won't be making a join-table. Also, it should not be needed. How can I make a List<User> users that simply is a list of User where User.groupId == UserGroup.Id?
I think you need the mappedBy="UserGroup" in the #OneToMany annotation.