spring data r2dbc #createdBy field setting - spring

I've got an abstract BasicEntity class implementing Persistable.
It's purpose to set basic fields :
#CreatedDate
#Column(value = "create_time")
private Long createTime;
#CreatedBy
#Column(value = "create_user")
private String createUser;
#LastModifiedDate
#Column(value = "last_modify_time")
private Long lastModifyTime;
#LastModifiedBy
#Column(value = "last_modify_user")
private String lastModifyUser;
It sets
spring.application.name: my_app
to the field lastModifyUser and it makes a timestamp for the lastModifyTime, but createTime and createUser are nulls after saving entity. Any advice ?

You have two options.
In the entity you can indicate the annotation #EnableR2dbcAuditing
Or, create a configuration class
#Configuration
#EnableR2dbcAuditing
class DatabaseConfig{
}

Related

Ignore field for query in spring-r2dbc

I am using spring r2dbc and ReactiveCrudRepository in spring webflex applicaition.
I have a field which I need to ignore for when select query is generated
( in Controller code is r2dbcEntityTemplate.select(Tenant.class) ).
I try to using #Transient ,But It doesn't work, still error: "Required property daysRemaining not found for class Tenant"
With my limited experience with r2dbc, Thanks in advance.
#Accessors(chain = true)
#Table(value = "tenant")
#Data
#Builder
public class Tenant {
#Id
private Long id;
#Column(value = "organization_name")
private String organizationName;
#Version
#Column
private Long version;
#Column
private Boolean trialTenant;
#DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
#Column
private LocalDateTime tenantExpiredTime;
#Transient
//Dynamically calculate the remaining time
private Long daysRemaining;
public Long getDaysRemaining() {
return Optional.ofNullable(tenantExpiredTime)
.map(localDateTime -> Duration.between(localDateTime, LocalDateTime.now()))
.map(Duration::toDays)
.orElseGet(() -> null);
}
}
#ReadOnlyProperty annotation works.

Spring JPA bidirectional relation on multiple nested entities

I know there has been multiple questions on bidirectional relations using spring jpa in the past but my case is a little bit different because i am using 3 entities with 2 relationships to implement a medical system
I have 3 entities : doctor/patient/appointment
here is the code for the 3 entities
please note all setters , getters and constructors implemented but ommited here for clarity
Patient class
#Entity
public class resPatient {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String name;
private String gender;
private String email;
private String mobile;
private int age;
private String notes;
#OneToMany(mappedBy = "patient")
List<resPackageMembership> memberships;
#OneToMany(mappedBy = "patient")
List<resAppointment> appointments;
#OneToMany(fetch = FetchType.LAZY,mappedBy = "patient")
List<resMedImage> medImages;
Doctor class
#Entity
public class resDoctor {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String name;
private String mobile;
private String email;
private String gender;
private int age;
private String speciality;
#OneToMany(mappedBy = "doctor")
List<resAppointment> appointments;
Appointment class
#Entity
public class resAppointment {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String speciality;
#Basic
#Temporal(TemporalType.TIMESTAMP)
private Date dateCreated;
#Basic
#Temporal(TemporalType.TIMESTAMP)
private Date dateToVisit;
private String status;
private String notes;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "doctorCode")
private resDoctor doctor;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "patientCode")
private resPatient patient;
the way my medical system should work is that when i get a patient using my restful controller i want all the patient data including his appointments but this leads to an infinite loop as the appointment has the doctor which also has appointments and so on.
i cannot user #JSONIGNORE as there are 2 relationships i want to get the patient with his appointments which should have the doctor without the appointments array and should not have any patient data as i already am in the patient object
As a general best-practice, it's recommended to separate the entities from the data transfer objects used for the rest controllers. With DTO's in place, you have more control on which data to include and serialize within them to avoid the circlular references.
If you like check out https://bootify.io, it generates the DTOs from your database schema, but the custom endpoint you still need to define/build.
I develop an annotation processor called beanknife recently, it support generate DTO from any class. You need config by annotation. But you don't need change the original class. This library support configuring on a separate class. Of course you can choose which property you want and which you not need. And you can add new property by the static method in the config class. For your question:
// this will generate a DTO class named "resPatientView".
// You can change this name using genName attribute.
#ViewOf(value=resPatient.class, includePattern = ".*")
public class PatientViewConfigure {
// here tell the processor to automatically convert the property appointments from List<resAppointment> to List<resAppointmentWithoutPatient>.
// resAppointmentWithoutPatient is the generated class configured at the following.
// Note, although at this moment it not exists and your idea think it is an error.
// this code really can be compiled, and after compiled, all will ok.
#OverrideViewProperty("appointments")
private List<resAppointmentWithoutPatient> appointments;
}
// here generated a class named resAppointmentWithoutPatient whick has all properties of resAppointment except patient
#ViewOf(value=resAppointment.class, genName="resAppointmentWithoutPatient", includePattern = ".*", excludes={"patient"})
public class AppointmentWithoutPatientViewConfigure {
// the doctor property will be converted to its dto version which defined by the configure class DoctorWithoutAppointmentsViewConfigure.
#OverrideViewProperty("doctor")
private resDoctorWithoutAppointments doctor;
}
// here we generate a class which has all properties of resDoctor except appointments
#ViewOf(value=resDoctor.class, genName="resDoctorWithoutAppointments", includePattern = ".*", excludes={"appointments"})
public class DoctorWithoutAppointmentsViewConfigure {}
// in you rest controller. return the dto instead of the entities.
resPatient patient = ...
resPatientView dto = resPatientView.read(patient);
List<resPatient> patients = ...
List<resPatientView> dto = resPatientView.read(patients);
At the end, the class resPatientView will has the same shap with resPatient except its appointments not having patient property and its doctor property is replaced with a version without appointments property.
Here are more examples.
The version 1.10 is ready. Will fix some bug and support the configure bean to be managed by spring.

spring data mongo No property b found on entity class when retrieving entity by Id

I have a parent class that has some shared fields and a child class that extends it.
#SuperBuilder(toBuilder = true)
#Data
public abstract class MultiTenantAuthoredDocument {
#Indexed
private String tenantId;
#CreatedDate
private LocalDateTime createdDate;
#LastModifiedDate
private LocalDateTime lastModifiedDate;
}
#Document(collection = "users")
#SuperBuilder(toBuilder = true)
#Data
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
public class User extends MultiTenantAuthoredDocument {
#Id
private String id;
private String firstName;
private String lastName;
#Indexed
private String password;
#Indexed(unique = true)
private String userName;
#Indexed(unique = true)
private String email;
#Indexed
private List<UserRole> roles;
#Builder.Default
private boolean enabled = false;
}
However when running my unit tests, I get an unexpected exception when I do a findById and there's a result found namely:
No property b found on entity class be.moesmedia.erp.users.domain.User to bind constructor parameter to!
As I have no clue where property b is coming from it's pretty difficult to see what I'm doing wrong.
If anyone can help me point out what I'm doing wrong.
So I've figured out what was going wrong, Lombok generated a constructor that accepted an Object with the properties for the SuperBuilder class. Once I added #NoArgsConstructorto both the child and parent class, it works like a charm.

Spring + hibernate one to one mapping

I am developing web application using spring and hibernate. I am using one to one mapping between two tables employee and PersonelDetails.
below are my bean classes
=======================Employee=====================================
#Entity
#Table(name="employee")
public class Employee {
#Id
#Column
#GeneratedValue
private int empid;
#Column
private String firstName;
#Column
private String lastName;
#Column
private String email;
#Column
private String password;
#Column
private boolean isAdmin;
#Column
private boolean isActive;
#Column
private boolean isLocked;
//getter setters
====================PersonalDetails class====================
#Entity
#Table(name="PersonalDetails")
public class PersonalDetails {
#Column
#Id
private int empid;
#Column
private String personalEmail;
#Column
private String mob;
#Column
private String permenantAdress;
#Column
private String currentAddress;
#Column
private String gender;
#Column
private String maritialStatus;
#MapsId
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "empid", referencedColumnName = "empid")
#ForeignKey(name="empid")
private Employee employee;
//getter setters
In my application table employee is filled by Admin user while creating new employee after that employyee himself fill personalDetails table by login to his accountCreated by Admin)
Now when I try to send personal details bean to hibernate layer first I have to get the employee bean from employee table then call setEmployee method over personalDetails class and save employee bean in personalDetails and send to hibernate layer for saving in database.
So while getting employee bean from database and again send back through personalDetails bean leads to a performance issue.
Can anyone help here to clarify while saving data in child table(PersonalDetails) is it really mandatory to pass parent object(Employee) ?
=======================code to store personalDetails===============
#RequestMapping(value="addpersonal")
public ModelAndView addPersonalDetails(#ModelAttribute("personalDetails") PersonalDetails personalDetails) {
//personalDetails.setEmpid(1);
personalDetails.setCurrentAddress("niljyoti");
personalDetails.setMob("9405715872");
personalDetails.setPermenantAdress("address");
Employee e = empService.getEmployeebyUserName(uname);
personalDetails.setEmployee(e);
personalDetailsService.addPersonalDetails(personalDetails);
return new ModelAndView("home");
}
On read:
You can change fetch strategy if you are worried.
Based od JPA spec, default fetch type for #OneToOne is EAGER.
By setting fetch = FetchType.LAZY, instead of real PersonalDetails object, an object of a subclass behaving as a proxy is returned. Hence, selecting from employee table starts only after getEmployee is called.
On write:
You need to specify connection between entities, in your model, the only way is the employee field. However, you can specify mappedBy, see answer to this question:
Java: Hibernate #OneToOne mapping

how to insert/update an entity attribute that is annotated as #CreationTimestamp?

#Entity
#Table(name="transactions")
#NamedQuery(name="Transaction.findAll", query="SELECT t FROM Transaction t")
public class Transaction implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id", nullable=false, unique=true, length=11)
private int id;
#CreationTimestamp
#Column(name="created_at")
private Date createdAt;
}
I have above entity using with Hibernate. I have a requirement where I need to update createdAt field but when I try following it didn't work. The createdAt is from the date of creations, which make sense.
Transaction newTransaction = new Transaction();
newTransaction.setCreatedAT(new Date);
sessionFactory.openSession().save(newTransaction);
Is there a way to keep #CreationTimestamp annotation and be able to modify or set another date when needed ?
**I am using Hibernate 4 with Spring. Any solution or another suggestion will be highly appreciated **
Why would you want to set it manually? Much cleaner solution would be to have 2 methods in your entity class. Both annotations are from the persistence package.
private Date creationTime;
private Date modificationTime;
#PrePersist
public void prePersist() {
Date now = Date();
this.creationTime = now;
this.modificationTime = now;
}
#PreUpdate
public void preUpdate() {
this.modificationTime = Date();
}
Or preferably use Java 8/Jodatime classes, in which case you need set #Type for fields manually as Hibernate doesn't support them out of the box as far as I know.

Resources