ERROR: column "id" is of type uuid but expression is of type bytea in Hibernate 6 - spring

I am using Hibernate 6. I have a column defined in a postgres database as auuid.
However, I removed the type annotation for a postgres uuid because the type was removed from Hibernate 6. Now I get the following error:
ERROR: column "id" is of type uuid but expression is of type bytea
#Entity
public class SomeObject implements Serializable {
#EmbeddedId
#Access(AccessType.PROPERTY)
private SomeKey id;
}
#Embeddable
public class SomeKey implements Serializable {
private UUID id;
private int other;
}
SomeObject obj= new SomeObject();
obj.setId(new SomeKey (UUID.randomUUID(),0));
session.persist(obj);
Not sure how to fix. It was working before with #Type annotation.
Edit:
Seems like this also causes the same issue
#Basic
#JdbcTypeCode(SqlTypes.UUID)
private UUID id;

This is an incredibly hacky solution, but I was able to get it to work by creating a new PostgresUUIDType which mirrored the one from Hibernate 5.6.*.
That would get reads to work, but not writes. To fix writes, I had to also remove #Access(AccessType.PROPERTY).
So final working code looks like this:
#Entity
public class SomeObject implements Serializable {
#EmbeddedId
private SomeKey id;
}
#Embeddable
public class SomeKey implements Serializable {
#Type(value=PostgresUUIDType.class)
private UUID id;
private int other;
}

Related

JPA findTopBy cannot work on spring boot 2.6.3

I am studying spring-boot and JPA. the spring-boot version is 2.6.3, which is the latest current version.
I defined my entity class like:
#Entity
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int age;
private String name;
private String genre;
// ignore the getters, setters and toString()
And defined with one projection DTO interface.
public interface AuthorDto {
public String getName();
public int getAge();
}
then defined the repository as follows:
#Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {
Author findFirstByGenre(String genre);
AuthorDto findTopByGenre(String genre);
}
the method findFirstByXXX worked well, but the second method, AuthorDto findTopByGenre(String genre);, could not work well, and was ended up with the following error in the log:
Reason: Failed to create query for method public abstract com.bookstore.dto.AuthorDto com.bookstore.repository.AuthorRepository.findTopByGenre(java.lang.String)! Cannot invoke "java.lang.Class.isInterface()" because "typeToRead" is null; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract com.bookstore.dto.AuthorDto com.bookstore.repository.AuthorRepository.findTopByGenre(java.lang.String)! Cannot invoke "java.lang.Class.isInterface()" because "typeToRead" is null
I tested the same code on spring-boot 2.1.4.RELEASE, it could work well.
I tried to find any official documents on this, but didn't find useful thread on this.

Are there #MappedSuperclass in Spring Reactive Data (R2DBC)

I have a super Entity class like this:
#Getter
#Setter
#NoArgsConstructor
public class GenericEntity {
#Id
private Long id;
#JsonIgnore
#CreatedBy
private Long createdBy;
#JsonIgnore
#CreatedDate
private Long createdDate;
#JsonIgnore
#LastModifiedBy
private Long updatedBy;
#JsonIgnore
#LastModifiedDate
private Long updatedDate;
#JsonIgnore
#Version
private Integer version = 0;
}
and a Role class extends from GenericEntity like this:
#Getter
#Setter
#NoArgsConstructor
public class Role extends GenericEntity {
private String name;
private String desc;
private Integer sort;
}
And after that I have interface RoleRepo like this:
#Repository
public interface RoleRepo extends ReactiveCrudRepository<Role, Long>;
In Router function, I have 2 handler methods
private Mono<ServerResponse> findAllHandler(ServerRequest request) {
return ok()
.contentType(MediaType.APPLICATION_JSON)
.body(roleRepo.findAll(), Role.class);
}
private Mono<ServerResponse> saveOrUpdateHandler(ServerRequest request) {
return ok()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(request.bodyToMono(Role.class).flatMap(role -> {
return roleRepo.save(role);
}), Role.class);
}
The method findAllHandler works fine, but the saveOrUpdateHandler throw exception like this:
java.lang.IllegalStateException: Required identifier property not found for class org.sky.entity.system.Role!
at org.springframework.data.mapping.PersistentEntity.getRequiredIdProperty(PersistentEntity.java:105) ~[spring-data-commons-2.2.0.M2.jar:2.2.0.M2]
at org.springframework.data.r2dbc.function.convert.MappingR2dbcConverter.lambda$populateIdIfNecessary$0(MappingR2dbcConverter.java:85) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
But when I move
#Id
private Long id;
from GenericEntity class to Role class, the two methods work fine.
Are there any Annations #MappedSuperclass/JPA in Spring Reactive Data like that
I wish the id field in GenericEntity for all extends class
Thanks for your help
Sorry, my English so bad
I had a similar problem and after some search, I didn't find an answer to your question, so I test it by writing code and the answer is spring data R2DBC doesn't need #Mappedsuperclass. it aggregates Role class properties with Generic class properties and then inserts all into the role table without the need to use any annotation.

Spring Data Redis has strange result

I started using spring data redis in my project for temporary storing some data. Redis is new for me, I've never worked something similar to redis before (Key-Value).
So, traditionally I created repository via extending CrudRepository and my #RedisHash is:
#Data
#NoArgsConstructor
#AllArgsConstructor
#RedisHash(value = "employee", timeToLive = 100)
public class RedisEmployee implements Serializable {
#Id
private String id;
#Indexed
private Long employeeId;
private String fullName;
#Indexed
private String date;
#Indexed
private String companyName;
private String phone;
}
So it works fine but I noticed something strange for me, it's result when
I watch GUI.
This is all data when I save with CrudRepository only one "entity"
So, Look how much rows, I just save 1 #RedisHash value, it could be because of #Indexed annotation but anyway it looks very strange for me.
P.S.
I noticed that without #Indexed it's impossible to find anything, for example:
#Repository
public interface RedisEmployeeRepository extends CrudRepository<RedisEmployee, String> {
RedisEmployee findByDateAndCompanyNameAndEmployeeId(String date, String companyName, Long employeeId);
}
so, findByDateAndCompanyNameAndEmployeeId will not return result if I don't have all fields #Indexed. Can't understand it is proper or not.

Spring JPA saving distinct entities with composite primary key not working as expected, updates same entity

I have a logic that saves some data and I use spring boot + spring data jpa.
Now, I have to save one object, and after moment, I have to save another objeect.
those of object consists of three primary key properties.
- partCode, setCode, itemCode.
let's say first object has a toString() returning below:
SetItem(partCode=10-001, setCode=04, itemCode=01-0021, qty=1.0, sortNo=2, item=null)
and the second object has a toString returning below:
SetItem(partCode=10-001, setCode=04, itemCode=01-0031, qty=1.0, sortNo=2, item=null)
there is a difference on itemCode value, and itemCode property is belonged to primary key, so the two objects are different each other.
but in my case, when I run the program, the webapp saves first object, and updates first object with second object value, not saving objects seperately.
(above image contains different values from this post question)
Here is my entity information:
/**
* The persistent class for the set_item database table.
*
*/
#Data
#DynamicInsert
#DynamicUpdate
#Entity
#ToString(includeFieldNames=true)
#Table(name="set_item")
#IdClass(SetGroupId.class)
public class SetItem extends BasicJpaModel<SetItemId> {
private static final long serialVersionUID = 1L;
#Id
#Column(name="PART_CODE")
private String partCode;
#Id
#Column(name="SET_CODE")
private String setCode;
#Id
#Column(name="ITEM_CODE")
private String itemCode;
private Double qty;
#Column(name="SORT_NO")
private int sortNo;
#Override
public SetItemId getId() {
if(BooleanUtils.ifNull(partCode, setCode, itemCode)){
return null;
}
return SetItemId.of(partCode, setCode, itemCode);
}
#ManyToMany(fetch=FetchType.LAZY)
#JoinColumns(value = {
#JoinColumn(name="PART_CODE", referencedColumnName="PART_CODE", insertable=false, updatable=false)
, #JoinColumn(name="ITEM_CODE", referencedColumnName="ITEM_CODE", insertable=false, updatable=false)
})
private List<Item> item;
}
So the question is,
how do I save objects separately which the objects' composite primary keys are partially same amongst them.
EDIT:
The entity extends below class:
#Setter
#Getter
#MappedSuperclass
#DynamicInsert
#DynamicUpdate
public abstract class BasicJpaModel<PK extends Serializable> implements Persistable<PK>, Serializable {
#Override
#JsonIgnore
public boolean isNew() {
return null == getId();
}
}
EDIT again: embeddable class.
after soneone points out embeddable class, I noticed there are only just two properties, it should be three of it. thank you.
#Data
#NoArgsConstructor
#RequiredArgsConstructor(staticName="of")
#Embeddable
public class SetGroupId implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#NonNull
private String partCode;
#NonNull
private String setCode;
}
Check howto use #EmbeddedId & #Embeddable (update you might need to use AttributeOverrides in id field, not sure if Columns in #Embeddable works).
You could create class annotated #Embeddable and add all those three ID fields there.
#Embeddable
public class MyId {
private String partCode;
private String setCode;
private String itemCode;
}
Add needed getters & setters.
Then set in class SetItem this class to be the id like `#EmbeddedId´.
public class SetItem {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name="partCode",
column=#Column(name="PART_CODE")),
#AttributeOverride(name="setCode",
column=#Column(name="SET_CODE"))
#AttributeOverride(name="itemCode",
column=#Column(name="ITEM_CODE"))
})
MyId id;
Check also Which annotation should I use: #IdClass or #EmbeddedId
Be sure to implement equals and hashCode in SetGroupId.
Can you provide that class?

Spring data jpa persist nested changes

I have 3 classes:
Record/ Profile / Options
#Entity
#Table(name="Record")
public class Record implements Serializable {
#Id
#GeneratedValue
private int id;
#ManyToOne(cascade=CascadeType.MERGE)
#JoinColumn(name="ProfileId")
private Profile profile;
....
}
#Entity
#Table(name="Profile")
public class Profile implements Serializable {
#Id
#GeneratedValue
private int id;
#ManyToOne(cascade=CascadeType.MERGE)
#JoinColumn(name="OptionId")
private Option option;
....
}
#Entity
#Table(name="Option")
public class Option implements Serializable {
#Id
#GeneratedValue
private int id;
private String name;
....
}
let's say the original option is "50M" and then I change the record1.profile1.option to "10M"
Also when I do record1.setId(null);recordRepository.save(record1);
I want to create an new entry from record1(as a change history).
In this case because the option is nested, the cascade type of merge will not persist the changes happened in profile. Thus when I get the record back, it will still say that recordNew.profile1.option is 50M
But if I change the cascadeType to CascadeType.ALL or CascadeType.PERSISTin the Record class, when I try to save the new entry, it seems Spring Data JPA will complains about detached property as: org.hibernate.PersistentObjectException: detached entity passed to persist: com.test.lalala.profile.Profile
Is there a way that I could fix this?

Resources