I am developing a spring-boot application (jpa...etc), and I am stuck in one problem. I am using the UUID attribute for the primary keys. When I try to create object as foreign key, the jpa can't cast correctly to my object.
I tried to use a AttributeConverter, but jpa does not call it.
My UserEntity
#Entity(name = "User")
#Table(name = "USR")
#EntityListeners(UserPersistListener.class)
#EqualsAndHashCode
public class UserEntity {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(name = "ID", updatable = false)
#Getter
#Setter
private String id;
#Column(name = "LOGIN", updatable = false)
#Getter
#Setter
private String login;
#Column(name = "PASS")
#Getter
#Setter
private String pass;
#Enumerated(EnumType.STRING)
#Column(name = "ROLE")
#Getter
#Setter
private Role role;
}
My other Entity Person using UserEntity (foreign key)
#Entity(name = "Person")
#Table(name = "PERSON")
#EqualsAndHashCode
public class PersonEntity {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(name = "ID", updatable = false)
#Getter
#Setter
private String id;
#Column(name = "NAME")
#Getter
#Setter
private String name;
#Column(name = "SUBSCRIPTION")
#Getter
#Setter
private Long subscription;
#Enumerated(EnumType.STRING)
#Column(name = "SUBSCRIPTION_TYPE")
#Getter
#Setter
private SubscriptionType subscriptionType;
#Column(name = "PHONE1")
#Getter
#Setter
private Long phone1;
#Column(name = "PHONE2")
#Getter
#Setter
private Long phone2;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CREATED_BY", updatable = false)
#Getter
#Setter
private UserEntity createdBy;
#Convert(converter = LocalDateAttributeConverter.class)
#Column(name = "CREATION_DATE")
#Getter
#Setter
private LocalDateTime creationDate;
}
Exception
org.springframework.data.domain.PageImpl["content"]->java.util.Collections$UnmodifiableRandomAccessList[0]->br.com.orangesun.entity.person.PersonEntity["createdBy"]->br.com.orangesun.entity.user.UserEntity_$$_jvst424_1["id"])
2019-06-18 00:52:55.163 WARN 15432 --- [nio-8099-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42883
2019-06-18 00:52:55.164 ERROR 15432 --- [nio-8099-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: operator does not exist: uuid = character varying
Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
Edit
My database definition
| Field Name | Type |
|-----------------------------|
| id | uuid |
| name | varchar |
| subscription | int8 |
| subscription_type | varchar |
| created_by | uuid |
| creation_date | instant |
| phone1 | int8 |
| phone2 | int8 |
|-----------------------------|
EDIT 2
Other details about same error
java.lang.IllegalArgumentException: Provided id of the wrong type for class br.com.orangesun.entity.person.PersonEntity. Expected: class java.lang.String, got class java.util.UUID
Try to use UUID type instead of String for 'id' fields, because UUID is a binary format, not character based, so databases use special type for UUID fields.
Update your PersonEntity class as below,
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CREATED_BY", referencedColumnName = "ID”, updatable = false)
#Getter
#Setter
private UserEntity createdBy;
Add referencedColumnName to your #joinColumn
UUID in Postgres is automatically converted for you into UUID datatype. You must change your id datatype from String to UUID and everything will work as expected.
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(name = "ID", updatable = false)
#Getter
#Setter
private UUID id;
Use UUID instead of String.
Moreover, replace
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CREATED_BY", updatable = false)
by
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "CREATED_BY", referencedColumnName = "ID", updatable = false)
It gives:
The UserEntity:
#Entity(name = "User")
#Table(name = "USR")
#EntityListeners(UserPersistListener.class)
#EqualsAndHashCode
public class UserEntity {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(name = "ID", updatable = false)
#Getter
#Setter
private UUID id;
#Column(name = "LOGIN", updatable = false)
#Getter
#Setter
private String login;
#Column(name = "PASS")
#Getter
#Setter
private String pass;
#Enumerated(EnumType.STRING)
#Column(name = "ROLE")
#Getter
#Setter
private Role role;
}
The other Entity Person using UserEntity (foreign key)
#Entity(name = "Person")
#Table(name = "PERSON")
#EqualsAndHashCode
public class PersonEntity {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(name = "ID", updatable = false)
#Getter
#Setter
private UUID id;
#Column(name = "NAME")
#Getter
#Setter
private String name;
#Column(name = "SUBSCRIPTION")
#Getter
#Setter
private Long subscription;
#Enumerated(EnumType.STRING)
#Column(name = "SUBSCRIPTION_TYPE")
#Getter
#Setter
private SubscriptionType subscriptionType;
#Column(name = "PHONE1")
#Getter
#Setter
private Long phone1;
#Column(name = "PHONE2")
#Getter
#Setter
private Long phone2;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "CREATED_BY", referencedColumnName = "ID", updatable = false)
#Getter
#Setter
private UserEntity createdBy;
#Convert(converter = LocalDateAttributeConverter.class)
#Column(name = "CREATION_DATE")
#Getter
#Setter
private LocalDateTime creationDate;
}
as per OP gmrosa's own prior edit to the question.
Related
Try to learn hibernate + jpa, don`t know what to do with this. Error when getting by id.
JDBC exception executing SQL [select u1_0.id,u1_0.email,u1_0.login,u1_0.password,r1_0.id,r1_0.name from user u1_0 left join role r1_0 on r1_0.id=u1_0.role_id where u1_0.id=?]
Caused by: org.postgresql.util.PSQLException: ERROR: column u1_0.role_id doesn`t exist
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(nullable = false, unique = true)
private String login;
#Column(nullable = false)
private String password;
#Column(nullable = false, unique = true)
private String email;
#ManyToOne
#JoinColumn(name = "role_id")
private UserRole role;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "role")
public class UserRole {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(nullable = false)
private String name;
}
enter image description here
Tried to debug but no results
I have the following entity in SpringBoot and I would like to create a new entity which has the userID of the registered user and the name of the registered/logged in user as instance fields/table columns.
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name="User")
public class WebUser {
#Id
#GeneratedValue
private Long userID;
#NonNull
private String name;
#NonNull
private String email;
#NonNull
private String password;
}
How would I go about doing this using a form in SpringBoot and JPA entity? I am struggling, I tried to create a form with hidden input fields using #OneToMany annotation but the userID and name were null.
Thanks for any help
Frist of all you Should define table column names using #Column(name = "COLUMN_NAME") and assume your new entity name LogUser.
LogUser
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name="LogUser")
public class LogUser{
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID", nullable = false)
private WebUser webUser;
#Column(name = "NAME", nullable = false)
private String name;
}
WebUser
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name="User")
public class WebUser {
#Id
#GeneratedValue
#Column(name = "USER_ID")
private Long userID;
#Column(name = "NAME", nullable = false)
private String name;
#Column(name = "EMAIL", nullable = false)
private String email;
#Column(name = "PASSWORD", nullable = false)
private String password;
#OneToMany(mappedBy = "webUser")
private Set<LogUser> logUsers;
}
I have already seen topics with this question, but they did not help me. Maybe I didn't see something.
Below I attach the code and the error.
#Entity
#Table(name = "department")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#EqualsAndHashCode
public class Department {
#Id
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#GeneratedValue(strategy = GenerationType.IDENTITY, generator = "uuid2")
#Column(length = 36, nullable = false, updatable = false)
private UUID id;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(mappedBy = "department", cascade = CascadeType.ALL, fetch = FetchType.LAZY,
orphanRemoval = true)
private Set<User> userSet = new HashSet<>();
}
AND user
#Entity
#Table(name = "user")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#EqualsAndHashCode
public class User {
#Id
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#GeneratedValue(strategy = GenerationType.IDENTITY, generator = "uuid2")
#Column(length = 36, nullable = false, updatable = false)
private UUID id;
private String firstName;
private String lastName;
private Integer age;
#ManyToOne
#JoinColumn(name = "dep_id", nullable = true)
private Department department;
#ManyToMany
#JoinTable(
name = "device_devices",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "device_id"))
Set<Device> devices = new HashSet<>();
}
and service
#Override
public List<DepartmentDto> getAllDepartment() {
List<Department> all = departmentRepository.findAll();
return all.stream().map(mapper::toDepartmentDto).collect(Collectors.toList());
}
#Override
public UUID createDepartment(DepartmentDto departmentDto) {
Department entity = mapper.DtoToDepartment(departmentDto);
return departmentRepository.save(entity).getId();
}
#Override
public void deleteDepartment(UUID id) {
departmentRepository.deleteById(id);
}
#Override
#Transactional
public void addUserToDepartment(UUID departmentId,UUID userId){
Department department = departmentRepository.findById(departmentId).orElseThrow(DepartmentNotFoundException::new);
User user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new);
department.getUserSet().add(user); // ERROR java.lang.NullPointerException: null
user.setDepartment(department);
}
I think I did something wrong. I tried writing Cascade.ALL but it didn't help me. I don't think I fully understand the concept of a link collection yet. I don't like that in my code, I add the user to the department, and then I add the department to the user. Probably it can be done in one action.
Task.
I want to make a department and 2 functions. Add a user to the department and remove users from the department. in such a way that the contempt of the users from the department the user himself was not removed.
I will be glad to hear your comments
if you use #Builder annotation on top of the class
and you want to set default value for a field,
you must put annotation #Builder.Default on top of field
#Builder.Default
Set<Device> devices = new HashSet<>();
otherwise devices will always be NULL when the builder builds the object
I'm trying to set simple entity with NamedEntityGraph on it. Unfortunately it won't work. Could you have any ideas how to fix it?
ServiceType entity has #ElementCollection of with Set of String which are simply ids of PictureModel associated with entity. On run I got:
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [backgroundPicIds] on this ManagedType [pl.mihome.djcost.model.ServiceType]
#Entity
#Table(name = "service_type")
#Getter
#Setter
#NoArgsConstructor
#NamedEntityGraph(
name = "serviceType.with.backgroundPicIds",
attributeNodes = #NamedAttributeNode("backgroundPicIds")
)
public class ServiceType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(AccessLevel.NONE)
#Column(nullable = false, updatable = false)
private int id;
#Length(max = 100)
#NotBlank
private String name;
private boolean active;
#OneToMany(mappedBy = "serviceType")
private Set<Account> accounts;
#ManyToMany(mappedBy = "servicesApplicable")
private Set<AccountType> accountTypes;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "serviceType", orphanRemoval = true, cascade = CascadeType.ALL)
private Set<PictureModel> backgroundPicture;
#ElementCollection
#CollectionTable(name = "image", joinColumns = {#JoinColumn(name = "service_type_id")})
#Column(name = "id")
private Set<String> backgroundPictureId;
#PrePersist
void activate() {
this.active = true;
}
}
#Entity
#Table(name = "image")
#NoArgsConstructor
#Getter
#Setter
#Builder
#AllArgsConstructor
public class PictureModel {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Column(nullable = false, updatable = false)
#Setter(AccessLevel.NONE)
private String id;
private String type;
private String name;
#Lob
private byte[] body;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "account_id")
private Account account;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "public_platform_id")
private PublicPlatform publicPlatform;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "service_type_id")
private ServiceType serviceType;
}
You simply do not have an attribute with the name backgroundPicIds in the entity ServiceType.
Try to correct your graph in this way:
#NamedEntityGraph(
name = "serviceType.with.backgroundPicIds",
attributeNodes = #NamedAttributeNode("backgroundPictureId")
)
I'm trying to write tests and using in memory DB. My problem is to create schema for tests from hibernate entities.
I have such entities
#Entity
#Table(name = "users", schema = "public")
#Getter
#Setter
#NoArgsConstructor
public class User {
#Id
#Column(name = "user_id", updatable = false, nullable = false, unique = true)
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID id;
#Column(name = "name")
private String name;
#Column(name = "product")
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
#JoinTable(name = "products_users",
joinColumns = {#JoinColumn(name = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "product_id")})
private Set<Product> products;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd#HH:mm:ss")
#Column(name = "created_on")
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Date createdOn;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd#HH:mm:ss")
#Column(name = "modified_on")
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Date modifiedOn;
public User(String name, Set<Product> products, Date createdOn, Date modifiedOn) {
this.name = name;
this.products = products;
this.createdOn = createdOn;
this.modifiedOn = modifiedOn;
}
}
#Entity
#Table(name = "product", schema = "public")
#Getter
#Setter
#NoArgsConstructor
public class Product {
#Id
#Column(name = "product_id", updatable = false, nullable = false, unique = true)
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID id;
#Column(name = "name")
private String name;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd#HH:mm:ss")
#Column(name = "created_on")
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Date createdOn;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd#HH:mm:ss")
#Column(name = "modified_on")
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Date modifiedOn;
public Product(String name, Date createdOn, Date modifiedOn) {
this.name = name;
this.createdOn = createdOn;
this.modifiedOn = modifiedOn;
}
}
#Entity
#Table(name = "products_users", schema = "public")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class ProductsUsers {
#Id
#Column(name = "user_id", updatable = false, nullable = false, unique = true)
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private UUID userId;
#Column(name = "product_id")
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private UUID productId;
}
and
application.properties
spring.output.ansi.enabled=ALWAYS
server.port=8081
debug=true
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=123
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
And I have
application.properties
in tests package
spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS public;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.properties.hibernate.default_schema=public
And I get such exception
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error
executing DDL "alter table "public"."products_users" drop constraint
"FK2w1ylwiyjuy67n1ycr5lv5or3"" via JDBC Statement
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table
"products_users" not found; SQL statement: alter table
"public"."products_users" drop constraint
"FK2w1ylwiyjuy67n1ycr5lv5or3"