I have a tables called Category and CategorySet.
CREATE TABLE CATEGORY
(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
category_name VARCHAR(40) NOT NULL,
description VARCHAR(255),
uuid VARCHAR(40)
);
CREATE TABLE CATEGORY_SET
(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
parent INT NOT NULL,
child INT NOT NULL UNIQUE,
FOREIGN KEY (parent) REFERENCES CATEGORY (id),
FOREIGN KEY (child) REFERENCES CATEGORY (id)
);
Category.java
#Entity
#Table(name = "CATEGORY")
public class Category implements Serializable{
#Id
#Column(name = "ID")
#GeneratedValue
private Integer id;
#Column(name = "CATEGORY_NAME", nullable = false, length = 40)
private String name;
#Column(name = "DESCRIPTION", nullable = false, length = 255)
private String description;
#Column(name = "UUID", nullable = false, length = 40)
private String uuid;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "CATEGORY_SET", joinColumns = {#JoinColumn(name = "PARENT")}, inverseJoinColumns = {#JoinColumn(name = "CHILD")})
private Collection<Category> subCategories = new LinkedHashSet<Category>();
public Category(String name, String description, String uuid, Collection<Category> categorySets) {
this.name = name;
this.description = description;
this.uuid = uuid;
this.categorySets = categorySets;
}
}
I want to get all root categories which means they are not child category of any.
sql to get the result is:
SELECT DISTINCT CATEGORY.id
FROM CATEGORY
JOIN CATEGORY_SET
ON CATEGORY.id = CATEGORY_SET.parent
WHERE CATEGORY.id NOT IN (SELECT child
FROM CATEGORY_SET);
Can someone help me write HQL for this.
The HQL query is:
select c
from Category c
where c.id not in (select child from CategorySet)
Related
Im learning Hibernate and cant solve problem.
Why Hibernate does delete in table "writer_post" after update entity Writer?
Table writer_post have writer_id and post_id entity(Writer, Post) and have annotation #MoreToOne.
What did I do wrong?
Update:
I updating existing Writer. Same in table existing row for Writer.
Example:
Writer: id: 1, first_name: Dmitry, last_name: Polischuk.
Writer_post: writer_id: 1, post_id: 1.
I does update parameter only last_name.
Create tables
CREATE TABLE IF NOT EXISTS Label(
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS Writer(
id SERIAL PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL
);
CREATE TABLE IF NOT EXISTS Post(
id SERIAL PRIMARY KEY,
content VARCHAR(100) NOT NULL,
create_date TIMESTAMP DEFAULT NULL,
updated_date TIMESTAMP DEFAULT NULL,
status VARCHAR(30) NOT NULL
);
CREATE TABLE IF NOT EXISTS Post_Label(
label_id INT NOT NULL,
post_id INT NOT NULL,
FOREIGN KEY (post_id) REFERENCES Post(id) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (label_id) REFERENCES Label(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS Writer_Post(
post_id INT NOT NULL,
writer_id INT NOT NULL,
FOREIGN KEY (post_id) REFERENCES Post(id) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (writer_id) REFERENCES Writer(id) ON DELETE CASCADE ON UPDATE CASCADE
);
Entity Writer
#Getter
#Setter
#RequiredArgsConstructor
#Entity
#Table(name = "Writer")
public class Writer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#ManyToOne(targetEntity = Post.class, cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
#JoinTable(name = "writer_post",
joinColumns = #JoinColumn(name = "writer_id"),
inverseJoinColumns = #JoinColumn(name = "post_id"))
private List<Post> posts;
Entity Post
#Getter
#Setter
#RequiredArgsConstructor
#Entity
#Table(name = "Post")
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "Content")
private String content;
#Column(name = "create_date")
private Date created;
#Column(name = "updated_date")
private Date updated;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private PostStatus status;
#ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
#JoinTable(name = "post_label",
joinColumns = #JoinColumn(name = "post_id"),
inverseJoinColumns = #JoinColumn(name = "label_id"))
private List<Label> labels;
Code for update Writer
#Override
public Writer update(Writer writer) {
try(Session session = HibernateUtil.getSessionFactory().openSession()){
session.beginTransaction();
session.saveOrUpdate(writer);
session.getTransaction().commit();
return writer;
}
}
Result stacktrace
Hibernate: update Writer set first_name=?, last_name=? where id=?
Hibernate: delete from writer_post where writer_id=?
Your mapping looks like one post can be mapped to many writers. I guess you meant vice-versa. So, it's worth trying to change this:
#ManyToOne(targetEntity = Post.class, cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
#JoinTable(name = "writer_post",
joinColumns = #JoinColumn(name = "writer_id"),
inverseJoinColumns = #JoinColumn(name = "post_id"))
private List<Post> posts;
to this:
#OneToMany(targetEntity = Post.class, cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
#JoinTable(name = "writer_post",
joinColumns = #JoinColumn(name = "writer_id"),
inverseJoinColumns = #JoinColumn(name = "post_id"))
private List<Post> posts;
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 have a many to many relationship between user and group with addtional columns in the join table. It looks like this:
When I delete an user, it should remove all his references from user_to_group(which works) and all the groups created by him should remain and have their created_by field updated to NULL(this doesn't happen, all the entries are deleted).
DDL for schema:
CREATE TABLE user (
user_id int NOT NULL AUTO_INCREMENT,
first_name varchar(100) NOT NULL,
last_name varchar(100) NOT NULL,
username varchar(100) NOT NULL,
email_address varchar(100) UNIQUE NOT NULL,
phone_number varchar(100) NOT NULL,
password varchar(255) NOT NULL,
notification_type varchar(30) NOT NULL DEFAULT "email",
date_created datetime NOT NULL,
is_active bool NOT NULL DEFAULT false,
CONSTRAINT user_pk PRIMARY KEY (user_id)
);
CREATE TABLE `group` (
group_id int NOT NULL AUTO_INCREMENT,
name varchar(100) NULL,
date_created datetime NOT NULL,
is_private bool NOT NULL DEFAULT false,
created_by int NULL,
CONSTRAINT group_pk PRIMARY KEY (group_id),
CONSTRAINT group_user_fk FOREIGN KEY(created_by)
REFERENCES user (user_id) ON DELETE SET NULL
);
CREATE TABLE user_to_group (
user_id int NOT NULL,
group_id int NOT NULL,
user_type_id int NOT NULL,
is_blocked bool NOT NULL DEFAULT false,
CONSTRAINT user_to_group_pk PRIMARY KEY (user_id,group_id),
CONSTRAINT user_to_group_group_fk FOREIGN KEY(group_id)
REFERENCES `group` (group_id),
CONSTRAINT user_to_group_user_type_fk FOREIGN KEY(user_type_id)
REFERENCES user_type (id),
CONSTRAINT user_to_group_user_fk FOREIGN KEY(user_id)
REFERENCES user (user_id)
);
User Entity:
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "username",
unique = true)
private String username;
#Column(name = "email_address",
unique = true)
private String emailAddress;
#Column(name = "phone_number")
private String phoneNumber;
#Column(name = "password")
private String password;
#Column(name = "notification_type",
insertable = false)
private String notificationType = "email";
#Column(name = "date_created")
private Date dateCreated;
#Column(name = "is_active",
insertable = false)
private Boolean active = false;
#OneToMany(
mappedBy = "user",
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
orphanRemoval = true
)
private List<UserGroup> groups;
}
Group Entity:
#Entity
#Table(name = "`group`")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "group_id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "date_created")
private Date dateCreated;
#Column(name = "is_private",
insertable = false)
private Boolean privateG = false;
#OneToOne(fetch = FetchType.LAZY,
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
orphanRemoval = true)
#JoinColumn(name = "created_by")
private User createdBy;
#OneToMany(
mappedBy = "group",
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
orphanRemoval = true
)
private List<UserGroup> users = new ArrayList<>();
}
UserGroup(join table):
#Entity
#Table(name = "user_to_group")
public class UserGroup {
#EmbeddedId
private UserGroupId id;
#ManyToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
#MapsId("userId")
#JoinColumn(name = "user_id", insertable = false, updatable = false)
private User user;
#ManyToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
#MapsId("groupId")
#JoinColumn(name = "group_id", insertable = false, updatable = false)
private Group group;
#Column(name = "is_blocked",
insertable = false)
private boolean isBlocked = false;
}
Ignore user_type_id field on the join table. If I delete an user with on the workbench, it works as expected(created_by field updates to NULL). But if i use this:
#Override
#Transactional
public User deleteUser(Long id) {
Optional<User> userToDelete = userRepository.findById(id);
userToDelete.ifPresent(user -> userRepository.delete(user));
return userToDelete.orElseThrow(() -> new UserNotFoundException("User not found"));
}
the entire row in the group table is deleted. What am I doing wrong?
#ManyToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
#MapsId("groupId")
#JoinColumn(name = "group_id", insertable = false, updatable = false)
private Group group;
exclude CascadeType.REMOVE and group will be intact.
I have 2 tables in database side(oracle)
create table GROUPS
(
ID NUMBER not null,
GROUP_NAME VARCHAR2(30)
)alter table GROUPS
add constraint ID primary key (ID)
and
create table ITEM_GROUP
(
ITEM_ID VARCHAR2(30) not null,
GROUP_ID NUMBER not null
)
alter table ITEM_GROUP
add constraint ITEM_GROUPD_ID primary key (ITEM_ID, GROUP_ID)
alter table ITEM_GROUP
add constraint ITEM_GROUP_FK01 foreign key (GROUP_ID)
references GROUPS (ID);
Than I have mapping classes in Java side. I want to make thing, when I am selecting group to take all his items too, and I want to save item with hibernate it is all .
#Entity
#Table(name = "GROUPS")
public class Group {
#Id
#Column(name = "ID", nullable = false)
#javax.persistence.SequenceGenerator(name = "groupIdGenerator", sequenceName = "GROUP_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "groupIdGenerator")
private int id;
#Column(name = "GROUP_NAME")
private String groupName;
#JsonManagedReference
#OneToMany(fetch = FetchType.EAGER, mappedBy="group",cascade = CascadeType.ALL)
private List<GroupItems> groupItems = new ArrayList<>();
// setters and getters
}
#SuppressWarnings("serial")
#Embeddable
public class GroupItemPK implements Serializable {
#Column(name = "ITEM_ID")
private String merchantId;
#Column(name = "GROUP_ID")
private int id;
// getters , setters , constructors , equals hashcode methods
}
#Entity
#Table(name = "ITEM_GROUP")
public class GroupITEM {
#EmbeddedId
private GroupITEMtPK id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID")
#JsonBackReference
private Group group;
}
I am interested in did i make any mistakes in build relationship ? If I did what is my mistakes , because I can not do my select and save queries without exceptions.
I am trying to do in my Code
List<Group> list = sessionFactory.getCurrentSession().createQuery("from Group a").list();
and here is my Exception
org.hibernate.engine.jdbc.spi.SqlExceptionHelper could not extract ResultSet [n/a]
java.sql.SQLSyntaxErrorException: ORA-00904: "GROUPITE0_"."ID": invalid identifier
I'm doing Spring Boot project and use spring-boot-jpa (Hibernate implementation). I'm having trouble configuring following relation between entities.
Let's assume I need many-to-one (and reversly one-to-many) relation between two tables (MySQL in this example, table1 logically stores description for codes in various other tables) :
CREATE TABLE `table1` (
`id` INT NOT NULL AUTO_INCREMENT,
`ref_table` VARCHAR(50) NOT NULL,
`ref_column` VARCHAR(50) NOT NULL,
`code` VARCHAR(10) NOT NULL,
`description` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `u_composite1` (`ref_table` ASC, `ref_column` ASC, `code` ASC));
CREATE TABLE `table2` (
`id` INT NOT NULL AUTO_INCREMENT,
`field1` VARCHAR(100) NULL,
`code` VARCHAR(10) NOT NULL,
PRIMARY KEY (`id`));
The way I join these two tables in SQL is like this:
SELECT t2.*, t1.description
FROM table2 t2
JOIN table1 t1
ON ( t1.ref_table = 'table2'
AND t1.ref_column = 'code'
AND t1.code = t2.code);
So, I created entities like this (minus the getters an setters):
#Entity
#Table(name = "table1")
public class Table1 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false)
private int id;
#Column(nullable = false, length = 10)
private String code;
#Column(length = 100)
private String description;
#Column(name = "ref_column", nullable = false, length = 50)
private String refColumn;
#Column(name = "ref_table", nullable = false, length = 50)
private String refTable;
#OneToMany(mappedBy = "table1")
private List<Table2> table2;
}
#Entity
#Table(name = "table2")
public class Table2 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false)
private int id;
#Column(nullable = false, length = 45)
private String field1;
#ManyToOne(fetch=FetchType.LAZY)
#Column(name = "code")
#JoinColumns({
#JoinColumn(name = "code", referencedColumnName = "code", nullable = false, updatable = false),
#JoinColumn(name = "'table2'", referencedColumnName = "ref_table", nullable = false, updatable = false),
#JoinColumn(name = "'code'", referencedColumnName = "ref_column", nullable = false, updatable = false)
})
private Table1 table1;
}
But it doesn't work. :(
Can this kind of relation even be defined in JPA?
If so, please, how?
Pertaining to the "join with constant values" problem I managed to make it work using the #Where Hibernate annotation:
How to replace a #JoinColumn with a hardcoded value?
#Entity
#Table(name = "a")
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public long id;
#OneToMany
#JoinColumn(name = "id", referencedColumnName = "id")
#Where(clause = "blah = 'CONSTANT_VALUE'")
public Set<B> b;
protected A() {}
}
#Entity
#Table(name = "b")
public class B {
#Id
#Column(nullable = false)
public Long id;
#Column(nullable = false)
public String blah;
protected B() {}
}