How to do fetch select for #ManyToMany load via spring-data? - java

I try load roles of the user with User entity via #ManyToMany for auth, but I get Exception.
ERROR: column user0_.role_id does not exist
I just started to learn spring data. Please help me fix this issue. Thank You.
User entity:
#Entity(name = "users")
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "role_id")
private int roleId;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "user_id_role_id"
,
joinColumns = {
#JoinColumn(name = "user_id",
nullable = false,
updatable = false)
},
inverseJoinColumns = {
#JoinColumn(name = "role_id",
nullable = false,
updatable = false)
}
)
private List<Role> authorities;
#Column(name = "account_non_expired")
private boolean accountNonExpired;
#Column(name = "account_non_locked")
private boolean accountNonLocked;
#Column(name = "credentials_non_expired")
private boolean credentialsNonExpired;
#Column(name = "enabled")
private boolean enabled;
...
And Role entity:
#Entity(name = "user_role")
public class Role implements GrantedAuthority {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "role")
private String role;
...
My PostgreSQL schema:
CREATE TABLE IF NOT EXISTS user_role (
id SERIAL PRIMARY KEY,
role VARCHAR(10) NOT NULL
);
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(20) UNIQUE NOT NULL,
password VARCHAR(20) UNIQUE NOT NULL,
account_non_expired BOOLEAN NOT NULL DEFAULT TRUE,
account_non_locked BOOLEAN NOT NULL DEFAULT TRUE,
credentials_non_expired BOOLEAN NOT NULL DEFAULT TRUE,
enabled BOOLEAN NOT NULL DEFAULT TRUE
);
CREATE TABLE user_id_role_id (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
FOREIGN KEY (role_id) REFERENCES user_role (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);

Error indicates that you don't have property role_id in table user.
You have this property in entity:
#Column(name = "role_id")
private int roleId;
but when you create table:
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(20) UNIQUE NOT NULL,
password VARCHAR(20) UNIQUE NOT NULL,
account_non_expired BOOLEAN NOT NULL DEFAULT TRUE,
account_non_locked BOOLEAN NOT NULL DEFAULT TRUE,
credentials_non_expired BOOLEAN NOT NULL DEFAULT TRUE,
enabled BOOLEAN NOT NULL DEFAULT TRUE
);
you don't have property role_id.
Just remove property roleId from User entity and it should work :)

Related

Spring Boot Jpa relationship with part of Embeded Id

I am creating entity relationships in Spring Boot data JPA. Since those tables being legacy I am not able to modify or add columns. Issue is I am getting error if point part of embedded Id.
My entity classes looks like below:
Class Customer {
#EmbededId
private CustomerPk id;
#Column("NAME")
private String name;
#OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="customerDetails")
private List<Purchase> purchaseDetails;
...
}
#Embeddable
Class CustomerPk {
#Column("CUSTOMER_ID")
private String customerId
#Column("PURCHASE_ID")
private String productId;
#Column("PURCHASE_DATE")
private String date;
}
Purchase Entity looks like below:
Class Purchase {
#EmbededId
private PurchasePK id;
#Column("TRANSACTION_NAME")
private String transactionName;
#ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumns({
#JoinColumn(name="CUSTOMER_ID" referencedColumnName="CUSTOMER_ID")
#JoinColumn(name="PURCHASE_ID" referencedColumnName="PURCHASE_ID")
)}
private Customer customerDetails;
...
}
#Embeddable
Class PurchasePK {
#Column("CUSTOMER_ID")
private String customerId
#Column("PURCHASE_ID")
private String productId;
#Column("TRANSACTION_DATE")
private String date;
}
With above structure I am getting org.hibernate.AnnotationException: referencedColumnNames(CUSTOMER_ID, PURCHASE_ID) of Purchase.customerDetails referencing Customer not mapped to a single property.
If I remove date property from CustomerPK, I am able to make the server up. But with current requirement I need date to be part of the CustomerPK class.
I think if I use part of the composite key as Join Columns I am getting this error.
Working version:
#Entity
public class Customer {
#EmbeddedId
private CustomerPk id;
#Column(name = "NAME")
private String name;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "customerDetails")
private List<Purchase> purchaseDetails;
}
#Embeddable
public class CustomerPk implements Serializable {
#Column(name = "CUSTOMER_ID")
private String customerId;
#Column(name = "PURCHASE_ID")
private String productId;
#Column(name = "PURCHASE_DATE")
private String date;
}
#Entity
public class Purchase {
#EmbeddedId
private PurchasePK id;
#Column(name = "TRANSACTION_NAME")
private String transactionName;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID", insertable = false, updatable = false),
#JoinColumn(name = "PURCHASE_ID", referencedColumnName = "PURCHASE_ID", insertable = false, updatable = false),
#JoinColumn(name = "PURCHASE_DATE", referencedColumnName = "PURCHASE_DATE", insertable = false, updatable = false)
})
private Customer customerDetails;
}
#Embeddable
public class PurchasePK implements Serializable {
#Column(name = "CUSTOMER_ID")
private String customerId;
#Column(name = "PURCHASE_ID")
private String productId;
#Column(name = "TRANSACTION_DATE")
private String date;
}
Conclusion:
The provided information from #Ray was valid, you missed adding the required join columns to represent the full entity relation, regarding your note for the same #Ray point, yes you are right both columns usage is different but also both columns have their own name which it will not override any row value on runtime.
The result of the above tables and representation is as follows:
create table customer
(
customer_id varchar(255) not null,
purchase_date varchar(255) not null,
purchase_id varchar(255) not null,
name varchar(255),
primary key (customer_id, purchase_date, purchase_id)
);
create table purchase
(
customer_id varchar(255) not null,
transaction_date varchar(255) not null,
purchase_id varchar(255) not null,
transaction_name varchar(255),
purchase_date varchar(255),
primary key (customer_id, transaction_date, purchase_id)
);
alter table purchase
add constraint FK6rkrb8rq8x56kai7g5gm32d1y foreign key (customer_id, purchase_date, purchase_id) references customer;

Mysql Unique constraint over multiple columns

I have this table and, as the code shows, I have marked columns "cnpj, product, proposalNumber" as a unique composed constraint:
#Table(name = "Proposal", uniqueConstraints = {#UniqueConstraint(columnNames = {"cnpj", "product", "proposalNumber"})})
public class Proposal {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, updatable = false, insertable = false)
#JsonProperty("id")
private Long id;
#JsonProperty("cnpj")
#Column(name = "cnpj", nullable = false, length = 14)
private String cnpj;
#JsonProperty("proposalNumber")
#Column(name = "proposalNumber", nullable = false)
private String proposalNumber;
#JsonProperty("product")
#Column(name = "product", nullable = false, length = 100)
private String product;
#JsonProperty("price")
#Column(name = "price", nullable = false)
private BigDecimal price;
#JsonProperty("dueDate")
#Column(name = "dueDate", nullable = false)
private String dueDate;
#JsonProperty("qtyLife")
#Column(name = "qtyLife", nullable = false)
private Integer qtyLife;
#JsonIgnore
#Column(name = "active", nullable = false)
private Boolean active = true;
...
But, checking the DDL or DUMP ain't no unique information...
CREATE TABLE `proposal` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`active` bit(1) NOT NULL,
`cnpj` varchar(14) NOT NULL,
`due_date` varchar(255) NOT NULL,
`price` decimal(19,2) NOT NULL,
`product` varchar(100) NOT NULL,
`proposal_number` varchar(255) NOT NULL,
`qty_life` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
In addition to this, writing #Column(unique = true) on the column does not solve the problem either, it creates the unique constraint in the database but only referencing that single column, not the composition (cnpj, product and proposalNumber).
Any tips?
The problem is solved: nothing wrong with my solution, but I had to change my spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect to spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

Spring create DB repository for SQL table

I have 2 tables in MySql and I have mapped them using hibernate in Spring: users and roles .
I have created one more table: user_roles but I don't know how to map it in hibernate.
You can see the table structure below:
CREATE TABLE users (
username varchar(30) NOT NULL,
email varchar(50) NOT NULL,
password varchar(255) NOT NULL,
first_name varchar(40) NOT NULL,
last_name varchar(40) NOT NULL,
date_of_birth Date,
phone_number varchar(20),
PRIMARY KEY (username)
);
CREATE TABLE roles (
role_id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(255),
PRIMARY KEY (role_id)
);
CREATE TABLE user_roles (
username VARCHAR(30) NOT NULL,
role_id INTEGER NOT NULL,
PRIMARY KEY (username, role_id)
);
Here is the mapping for the roles tables:
#Entity
#Table(name = "roles")
public class Role implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="role_id")
private Integer id;
private String name;
}
Here is the mapping for the users table:
#Entity
#Table(name = "users")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class User implements Serializable {
#Id
#NotEmpty
#Size(min = 5, max = 15)
#Column(name = "username")
private String username;
#Email
#NotEmpty
#Column(name = "email")
private String email;
#NotEmpty
#Size(min = 5)
#Column(name = "password")
private String password;
#NotEmpty
#Size(max = 40)
#Column(name = "first_name")
private String firstName;
#NotEmpty
#Size(max = 40)
#Column(name = "last_name")
private String lastName;
...
}
I have created the POJO for the user_role table, but I don't know how to use hibernate on it, I am using #EmbeddedId annotation but it is not working. I don't know how to show the 2 classes above that they are embeddable
#Entity
#Table(name = "user_roles")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class UserRole implements Serializable {
public UserRole() { }
public UserRole(User username, Role role_id) {
this.username = username;
this.role_id = role_id;
}
private static final long serialVersionUID = -2947211066236048069L;
#EmbeddedId
private User username;
#EmbeddedId
private Role role_id;
}
How can I map the "UserRole" class to 'user_role' in hibernate? Thank you!
There are two different ways which you can map user_roles table, which I suggest the first one :
1.
#Entity
#Table(name = "users")
public class User
{
#ManyToMany(targetEntity = Role.class)
#JoinTable(name = "users_roles", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
#NotAudited
private Set<Role> roles = new HashSet<>();
}
2.
#Embeddable
public class UserRoleId implements java.io.Serializable
{
#Column(name = "user_id", nullable = false)
private long userId;
#Column(name = "role_id", nullable = false)
private long roleId;
public UserRoleId()
{
}
public UserRoleId(long userId, long roleId)
{
this.userId = userId;
this.roleId = roleId;
}
//hashcode equal
}
Then create the entity.
#Entity
#Table(name = "users_roles")
public class Userroles implements java.io.Serializable
{
#EmbeddedId
private UserRoleId id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false, insertable = false, updatable = false)
#NotNull
private Users users;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "role_id", nullable = false, insertable = false, updatable = false)
#NotNull
private Role role;
}

OneToMany mapping on Embeddable key

I am attempting to build a permission rule for accessing items (stored in table tab) by the users (stored in table users). The availability whether to see something is stored in permissions_tabs table.
The result should be as if the statement is run (for the user with id=2):
SELECT project.tab.tab_id, project.tab.parent, project.tab.name
FROM project.tab
INNER JOIN project.permissions_tabs
ON project.tab.tab_id=project.permissions_tabs.tab_id
WHERE permissions_tabs.user_id=2 AND permissions_tabs.view=true;
I am attempting to do it via the #OneToMany annotation, but it fails - I receive the message:
Deployment failed. The message was: Exception Description: The
#JoinColumns on the annotated element [field allowedTabs] from the
entity class [class
com.jtsmr.scheduler.persistence.entities.UsersEntity] 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.
Before amending the DB and adding the permissions_tab, it all worked. When I added it - I was unable to write the correct #OneToMany annotation, neither I succeeded in finding manual for my case.
If it is not possible, a solution via JPQL will suffice (I was unable to construct a join operation).
Here is my setup:
DB (creation statements for easier understanding):
CREATE TABLE `users` (
`user_id` bigint(20) NOT NULL,
`username` varchar(45) NOT NULL,
`password` varchar(45) NOT NULL,
`name` varchar(45) NOT NULL,
`email` varchar(80) NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_id_UNIQUE` (`user_id`),
UNIQUE KEY `username_UNIQUE` (`username`)
);
CREATE TABLE `tab` (
`tab_id` bigint(20) NOT NULL AUTO_INCREMENT,
`parent` bigint(20) NOT NULL DEFAULT '0',
`name` varchar(45) NOT NULL,
PRIMARY KEY (`tab_id`)
);
CREATE TABLE `permissions_tabs` (
`user_id` bigint(20) NOT NULL,
`tab_id` bigint(20) NOT NULL,
`to_view` bit(1) DEFAULT b'0',
`to_edit` bit(1) DEFAULT b'0',
PRIMARY KEY (`user_id`,`tab_id`),
KEY `user_id_idx` (`user_id`),
KEY `tab_id_idx` (`tab_id`),
CONSTRAINT `tab_id` FOREIGN KEY (`tab_id`) REFERENCES `tab` (`tab_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
);
The JPA Mapping is as follows (functions omitted):
Tabs:
#Entity
#Table(name = "tab")
public class TabEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "tab_id", insertable = false, updatable = false)
private Long tabId;
#Column(name = "parent", insertable = false, updatable = false)
private Long parent;
#Column(name = "name", insertable = false, updatable = false)
private String name;
}
Users:
#Entity
#Table(name = "users")
public class UsersEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long userId;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#OneToMany
#JoinTable(
name = "permissions_tabs",
joinColumns
= {
#JoinColumn(name = "user_id", referencedColumnName = "user_id")},
inverseJoinColumns
= {
#JoinColumn(name = "tab_id", referencedColumnName = "tab_id")})
private List<PermissionsTabsEntity> allowedTabs;
}
Primary key for the PermissionsTabsEntity class:
#Embeddable
public class PermissionsTabsPK implements Serializable {
#Column(name = "user_id")
private Long userId;
#Column(name = "tab_id")
private Long tabId;
}
And the PermissionsTabsEntity:
#Entity
#Table(name = "permissions_tabs")
public class PermissionsTabsEntity implements Serializable {
#EmbeddedId
private PermissionsTabsPK id;
#Column(name = "to_view")
private boolean toView;
#Column(name = "to_edit")
private boolean toEdit;
}
Thank you in advance!

Mapping java objects using hibernate annotations?

I am attempting to map two Java classes using Hibernate. When I compile I get the following error:
Caused by: org.h2.jdbc.JdbcSQLException: Column "COMMENTS0_.DELETED" not found;
Have compared to many examples and everything seems to be correct but there is obviously an error in my mapping. Here is my code:
SQL
-- Table 'TEST_STEP_COMMENT'
CREATE TABLE IF NOT EXISTS `TEST_STEP_COMMENT` (
`id` BIGINT NULL DEFAULT NULL AUTO_INCREMENT,
`test_step_comment` TEXT NOT NULL,
`date` DATETIME NOT NULL,
`test_step_id` BIGINT NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_TEST_STEP_COMMENT_TEST_STEPS`
FOREIGN KEY (`test_step_id`)
REFERENCES `TEST_STEPS` (`id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT);
CREATE INDEX `FK_TEST_STEP_COMMENT_TEST_STEPS_idx` ON `TEST_STEP_COMMENT` (`test_step_id` ASC);
CREATE TABLE IF NOT EXISTS `TEST_STEPS` (
`id` BIGINT NULL DEFAULT NULL AUTO_INCREMENT,
`deleted` BOOLEAN NULL DEFAULT FALSE,
`execute` LONGTEXT NOT NULL,
`sequence_order` INT NOT NULL,
`test_case_id` BIGINT NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_TEST_STEPS_TEST_CASES`
FOREIGN KEY (`test_case_id`)
REFERENCES `TEST_CASES` (`id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT);
CREATE INDEX `FK_TEST_STEPS_TEST_CASES_idx` ON `TEST_STEPS` (`test_case_id` ASC);
JAVA
#Entity
#Audited
#Table(name = "TEST_STEPS")
public class TestStep
extends AuditedEntity
implements Identifiable<Long>, Ordered<Integer>, Comparable<TestStep> {
#Id
#GeneratedValue
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "test_case_id")
private TestCase testCase;
#Column(name = "execute", nullable = false)
private String execute;
#OneToMany(mappedBy = "testStep", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#Filter(name = "deletedEntityFilter")
private Set<VerifyStep> verifications = Sets.newLinkedHashSet();
#Column(name = "sequence_order", nullable = false)
private Integer sequenceOrder = 0;
#OneToMany(mappedBy = "testStep", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<TestStepComment> comments = Sets.newLinkedHashSet();
#Column(name = "result")
private Integer result;
#Column(name = "data")
private String data;
//getters/setters etc
}
#Entity
#Audited
#Table(name = "TEST_STEP_COMMENT")
public class TestStepComment
extends AuditedEntity
implements Identifiable<Long>{
#Id
#GeneratedValue
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "test_step_id")
private TestStep testStep;
#Column(name = "test_step_comment")
private String comment;
#Column(name = "date")
private Date date;
#Override
public Long getId() {
return id;
//getters/setters etc
}
If anyone has any suggestions of what may be causing my problem it would be much appreciated because my mapping seems to be correct based on multiple examples that I have looked at. Thanks!

Categories

Resources