How to map java class to SQL view without id in spring data jpa? - spring

Here's my class
public class JobSteps {
private String jobNo;
private String stepNumber;
private String stepDescription;
}
And here's my view
JobNo CHAR(7),
StepNumber TEXT,
StepDescription TEXT
I tried to annotate my class with Entity, specifying the table name, but spring keeps complaining about id, I added #Id to JobNo, but spring complains about type. Is there a way to manage it? I have no access to the view and can't change anything there.

Fo example, You can add JobStepId class and wrap tit with your char column.
#Embeddable
class JobStepId implements Serializable {
String jobIdString;
Integer jobId;
//implements equals and hashCode
}
Then your class could imbed it:
#IdClass(JobStepId.class)
public class JobSteps {
#Id
private JobStepId jobNo;
private String stepNumber;
private String stepDescription;
}

Related

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

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;
}

Spring trying to set audit fields on null object

Spring-data-mongodb is trying to add createdDate to a null object and fails to do so. How do I configure spring audit to ignore null objects so it does not try to add audit fields to it?
I have an abstract class with all the audit info. Two classes (A,B) extend this abstract class and one of those two classes (A) has a reference to the other class (B) (that can be nullable). If I try to save an object of A with a null reference to B. It all fails because spring is trying to add audit info to the B null reference.
public abstract class AA {
#Id
private String id;
#Version
private Long version;
#CreatedDate
private LocalDateTime createdDate;
#LastModifiedDate
private LocalDateTime LastModifiedDate;
}
public class A extends AA {
private String name;
#Nullable
private B b;
}
public class B extends AA {
private String name;
}
public class ControllerA {
private AMongoRepository aMongoRepo;
public void saveSomeA(String name) {
A a = new A();
a.setName("Some Name");
a.setB(null);
aMongoRepo.save(a); // <-- Fails can not set createdDate on B null
}
}
The error message I get is the following.
org.springframework.data.mapping.MappingException: Cannot lookup property B A.b on null intermediate! Original path was: b.createdDate on A.
A quick google search brought me to jira.spring.io, which is the same issue I am having.
Any idea on how to cleanly handle this issue? Maybe move from inheritance to composition? Or should I just be patient an wait on the new version?

GraphQL SPQR: id shall not be shown at creation

I use GraphQL SPQR with the entity
#Entity
public class MyEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#GraphQLNonNull
#GraphQLQuery(name = "a", description = "Any field")
private String a;
// Getters and Setters
}
and the service
#Service
#Transactional
public class MyService {
#Autowired
private MyRepository myRepository;
#GraphQLMutation(name = "createEntity")
public MyEntity createEntity(#GraphQLArgument(name = "entity") MyEntity entity) {
myRepository.save(entity);
return entity;
}
}
In GraphiQL I am allowed to set the id:
mutation {
createEntity(entity: {
id: "11111111-2222-3333-4444-555555555555"
a: "any value"
}) {
id
}
}
But the id shall not be made editable to the user because it will be overwritten by the DB. It shall only be shown at the queries. I tried and added #GraphQLIgnore, but the id is shown all the same.
How can I hide the id at creation?
In GraphQL-SPQR version 0.9.9 and earlier, the private members are not scanned at all, so annotations on the private fields don't normally do anything. Incidentally, Jackson (or Gson, if so configured) is used to discover the deserializable fields on input types, and those libraries do look at private fields, so some annotations will appear to be working for input types. This is what is happening in your case. But, #GraphQLIgnore is not among the annotations that will work on a private field.
What you need to do is move the annotations to getters and setters.
#Entity
public class MyEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#GraphQLIgnore //This will prevent ID from being mapped on the input type
//#JsonIgnore would likely work too
public void setId(UUID id) {...}
}
There's other ways to achieve this, but this is the most straight-forward.
Note: In the future versions of SPQR (post 0.9.9), it will be possible to place the annotations on private fields as well, but mixing (placing some annotations on a field and some on the related getter/setter) will not work.

Redis #Reference does not work in Spring Data Redis

I am facing issues while implemeting #Reference in Spring Boot + Spring Data Redis. Address is a List in Employee and when I saved the office and home address and I was expecting the data to be saved with the Employee. But data did not get saved and hence unable to search the Address using street.
Employee.java
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
#RedisHash("employees")
public class Employee {
#Id #Indexed
private String id;
private String firstName;
private String lastName;
#Reference
private List<Address> addresses;
}
Address.java
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
#RedisHash("address")
public class Address {
#Id
private String id;
#Indexed
private String street;
private String city;
}
Test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EmployeeAdressTest extends RepositoryTestSupport{
#Autowired private EmployeeRepository employeeRepository;
#Before
public void setUp() throws JsonProcessingException {
Address home = Address.builder().street("ABC Street").city("Pune").build();
Address offc = Address.builder().street("XYZ Street").city("Pune").build();
Employee employee1 = Employee.builder().firstName("Raj").lastName("Kumar").addresses(Arrays.asList(home, offc)).build();
employeeRepository.save(employee1);
List<Employee> employees = employeeRepository.findByAddresses_Street("XYZ Street");
System.out.println("EMPLOYEE = "+employees);
}
#Test
public void test() {
}
}
Spring Doc:
8.8. Persisting References
Marking properties with #Reference allows storing a simple key reference instead of copying values into the hash itself. On loading from Redis, references are resolved automatically and mapped back into the object, as shown in the following example:
Example 30. Sample Property Reference
_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = al’thor
mother = people:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56
Reference stores the whole key (keyspace:id) of the referenced object.
?
Spring Data Redis requires you to save the objects stored in home and office separately from the referencing object employee1.
This is (now) stated in the official documentation at the very end of chapter 8.8: https://docs.spring.io/spring-data-redis/docs/current/reference/html/#redis.repositories.references
So if you save home and office to the database before saving employee1 you should be fine.
The same btw holds valid for updates you make to referenced objects later on. Just saving the referencing object alone does not save the updates on the referenced objects.

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?

Resources