self referencing object in JPA - spring

I am trying to save a SystemUser entity in JPA. I also want to save certain things like who created the SystemUser and who last modified the system User as well.
#ManyToOne(targetEntity = SystemUser.class)
#JoinColumn
private SystemUser userWhoCreated;
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(iso=ISO.DATE_TIME)
private Date timeCreated;
#ManyToOne(targetEntity = SystemUser.class)
#JoinColumn
private SystemUser userWhoLastModified;
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(iso=ISO.DATE_TIME)
private Date timeLastModified;
I also want to ensure that these values are not null when persisted. So If I use the NotNull JPA annotation, that is easily solved (along with reference to another entity)
The problem description is simple, I cannot save rootuser without having rootuser in the system if I am to use a DataLoader class to persist JPA entity. Every other later user can be easily persisted with userWhoModified as the "systemuser" , but systemuser it's self cannot be added in this scheme.
Is there a way so persist this first system user (I am thinking with SQL). This is a typical bootstrap (chicken or the egg) problem i suppose.

Have you tried rootUser.setUserWhoLastModified(rootUser) ?

Related

Passing a set of IDs or a set of objects as data in a DTO in Spring Boot?

I am trying to create a project management app and for my back-end I have a Project Entity which has a many-to-many relationship with the User Entity. I have the following DTO:
public class ProjectDto implements Serializable {
private final Long id;
private final String name;
private final String description;
private final Date createdAt;
private final Date updatedAt;
private final Set<UserDto> users;
}
And in my ProjectService I want to have a method which creates a project having any sent users assigned to it. However, my question is should my front-end send to my back-end a set of user objects or is better to send a set of IDs of the users I want to assign to this project ? Is it not better to actually have this DTO returned when a project is created and have another DTO with a set of user ids for when I want to create a project ?
We cannot trust data from front-end and should apply validations for the request body including Set<UserDto> users. And to validate the Set<UserDto> users we have to use trusted data - from DB, or other BE sources.
And using Set<?> userIds also needs to fetch from DB, but we don't have to add more code to do validate the DTO and validating the IDs is more simple and easy to maintain.
Using userIds is also to make sure the users that set to project are entities that fetched from DB. It also keeps the FE code simpler (I hope) as not having to build the (DTO) object

Optimistic locking - session based locking

I have a question related to optimistic locking in Spring/Hibernate actually.
I have following scenario with typical REST application with SQL database.
User A enters page and reads data - version 0 of entity - GET request
User B enters page and reads data - version 0 of entity - GET request
User A saves data - version 1 of entity - PUT request
User B wants to save data (PUT request), but I should see optimistic lock exception
Now my question:
Where hibernate saves data about entity version? I understand the situation when everything is in the same transaction:
Load data
Someone changed entity in the different transaction
Save data
But in my situation version will vanish GET and PUT are in totally different transaction/threads etc.
In my opinion I should save somewhere version loaded by the user to have correlation between GET and PUT requests e.g. in HTTP session or just return version in the response and then send that version in the PUT request.
Can it be done in the better way? Like out of the box?
JPA/Hibernate have #Version column in entity definition to check optimistic or pessimistic lockings. JPA/Hibernate saves versions in the table. For example you have Country table in db:
CREATE TABLE country (
id BIGINT NOT NULL AUTO_INCREMENT,
version BIGINT DEFAULT 0,
...
);
And Country entity:
#Entity
#Table(name = "country")
public class Country implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Version
#Column(name = "version")
private Long version;
...
}
If you update the country entity instances with optimistic lock conflicts, you get OptimisticLockException in JPA. You don't need to manage the versions, JPA/Hibernate checks the versions of entity instances for you.
Update for different transactions:
In different transactions you can get OptimisticLockException too because JPA/Hibernate checks in every update the version columns with database table. As long as you save your changes (commit), another changes of entity versions will be checked, doesn't matter whether in the same transaction or different transaction. Better you can manage your transactions with #Transactional annotation in Spring framework.

I am using Spring boot jpa with Restful api services to insert multiple users in array or list

As I am new to Spring boot. I am not at all clear about mappings. By using #Onetomany mapping in one entity and #manytoOne mapping at other entities. Using the controller I have to write REST API functions to insert multiple users at a time inside an array or set. Can anyone please suggest some websites or provide some existing codes?
The #OneToMany and #ManyToOne mappings can be used according to your use-case, whether you need bi-directional mappping or not. For a simple example consider the following :
#Entity
#Table(name="ENTITY_A")
public class EntityA{
//...
#OneToMany(mappedBy="EntityA")
private Set<EntityB> entityBItems;
// getters and setters
}
#Entity
#Table(name="ENTITY_B")
public class EntityB{
//...
#ManyToOne
#JoinColumn(name="entityA_id", nullable=false)
private EntityA entityA;
public EntityB() {}
// getters and setters
}
What you need to look out for is the owning side of the relation indicated by the mappedBy . The owning entity can be used to persist and get the data from the database. But from the description in your question I cannot understand whether you actually need to use mappings at all as you just have to insert multiple users into a table without any relations to another entity. It will be more helpful if you could explain more about your use case and provide code samples for furthur analysis.
For details about the mappings article or article .
Official doc .
MappedBy signals hibernate that the owner of key (relationship) is on the other side.
This means that although you link 2 tables together, only 1 of those tables has a foreign key constraint to the other one.
MappedBy allows you to still link from the table not containing the constraint to the other table.
If you still want use #JoinColumn on both the Entities you can use #JsonManagedReference and #JsonBackReference from com.fasterxml.jackson
To save the multiple records at same time you can use yourRepository.saveAll(entities)

how to make a spring jpa/correct repository when having mandatory relationships?

I have the following database which allows users to rent books in a book shop:
The entity class Book needs to have a Category as well as BookDescription when saved.
Those Book class looks like this:
#Entity
#Table(name = "books")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Book {
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "book_description_id")
private BookDescription bookDescription;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
private Category category;
//omitted fields, getters, setters & other relations
}
I was checking out Spring Data JPA. It has a signature of
CrudRepository<T, ID extends Serializable>
which means that I will have
CrudRepository<Book, String>
but how will I save a book?
So, generally, the user will submit a form, I will bind a BookUIObject which will contain all the details needed to save a book, pass it to a BookService witch will extract from it 3 objects: Book ( a specific implementation), Category and BookDescription. The question is will the service hook up the book relations and call the general repository.save(Book) or it will call a method like repository.save(Book, Category, BookDescription)?
Also, should I bind directly the data from the user into entity classes, or do like I said, bind to a general BookUIObject and let the service extract from it the entity classes?
Kind regards,
Typically you will have to call BookReporitory.save(book). Book has cascaring Persist for both of the relations, so if you have set the BookDescription and the Category on the book instance you save, they will also be persisted. If you didn't have cascading persist, you would have to save them using their JPARepository (unless they already existed in the Persistence context).
One thing that is important to understand in this example is that if you create a new category object and set it on a book and save the book a new category is created in the DB. So if the UI posts category=sic-fi, you have to check if the category already exists, if it does then you must used the managed category, and set that on the book rather than creating another "sci-fi" category. This is the reason I would not have cascading persist on the Category relation, because I would rather have a constraint violation because a category didn't exist, instead of an new category sci-if when someone miss spelled it in the UI.
I do not recommending binding forms directly to JPA entities, because you always need to fetch entities from JPA, as you have to use the managed versions, so in my experience it is better to have another set of beans for form binding.
Another thing that jumps out if the lack of nullable=false in #JoinColumn. If a book can't exist without being in a Category it is vital that this is communicated to the database, and if you generate tables from the JPA metadata model, this is how it is done. If I could give only one recommendation when working with databases/JPA it is to be overzealous with NOT NULL. It is a 100 time easier to get a constraint violation when you insert, than to get a NullPointerException later and have to check every possible code-path that could end up calling save and checking if the argument could be null.
In addition I would recommend that you set of some time to understand the concept of the EntityManager and the Persistence Context, most of the mistakes/assumptions developers make come back to the persistence context and how the 4 entity states work.

Postgresql and Spring Roo Binding serial type for ID

I am having trouble using the Postgresql serial type in Spring Roo. What I want is to have the an auto-incrementing id column which will work with the auto generated entity classes in Roo.
The Postgresql sequences, which are generated with the default way of doing things in Spring Roo, work fine within the spring application. But sometimes I have to manually insert rows in the database using sql. (the sequences dont seem to work properly when I do an INSERT INTO... statement). If I could use serial type, then manual INSERTS are easy.
For example I have an office entity and and employee entity. There is a many-to-one relationship between employees and offices.
Here is my class for the Office entity.
#RooJavaBean
#RooToString
#RooJpaActiveRecord
public class Office {
#Id
#Column(name="officeid", columnDefinition = "serial")
#Generated(GenerationTime.INSERT)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long officeid;
/**
* Office Name
*/
#NotNull
#Size(max = 100)
private String name;
}
While this does work when my test inserts an office record, it fails when an employee record is inserted since the officeid foreign key value is null. (I guess it needs to flush between the office insert and the employee insert, but the auto-generate tests dont seem to do that.)
So what is the proper annotations to use to tell Roo (and hibernate/jpa) to use the serial data type, and also to work properly with inserts and relationships within the spring application?
Roo generates default JPA annotations, you must customize and setup them as needed. Note Roo guarantees your changes won't be modified.

Resources