How to write query spring boot - spring-boot

I have classe notification has attribut receiver with type User like this :
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "sender", referencedColumnName = "id")
#JsonIgnore
private User sender;
and user has attribut bed :
#ManyToOne
(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "idBed")
#JsonIgnore
private Bed idBed;
and bed has attribut room :
#ManyToOne
(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "idroom")
#JsonIgnore
private Room room;
and room has attribut :
#ManyToOne
(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "idCarePost")
#JsonIgnore
private CarePost carePost;
please need to read all this data please how can i do it ?

You can use JPARepository. It will give the CRUD features out of the box you don't need to write any query. For example, if you use the save(object) method in the service class it will save the object no need to write the insert query.
If you want to write your custom query in the repository you can write by using #Query("write your custom query", nativeQuery = true) annotation.
#Repository
public interface BlogRepository extends JpaRepository<Post, Integer> {
#Query(value = "select * from posts p where p.author like %:value%", nativeQuery = true)
List<Post> findByAuthor(String value);
}
The above example is a way to write a native query using JPARepository.

You have jpa repository method as below.
Find user by some attribute as below.
List<User> findByName();
Find user by bed as below.
List<User> findByBed( bed object);
Find user by with continue object.
List<User> findByBedRoomCarePostName(string
carePostName);

Related

Spring Boot Entity how to check value if exist in another table by custom field

The user can search for products if any product shown in the result exists in the user_favorites table so the show flag tells the front-end this product was added for this user by user_id and product_id. with spring boot and spring data.
My Entity :
#Id
#Column(name = "catId")
private Integer catId;
#Column(name = "cat_no")
private String catNo;
#Column(name = "cat_sn")
private String catSn;
#Column(name = "doc_ref")
private String docRef;
#Column(name = "user_id")
private Integer userId;
#Column(name = "updated_at")
private String updatedAt;
#Column(name = "created_at")
private String createdAt;
I tried that using #Formula but nothing happing always returns null. and if it's done by #Formula how can i add parameters to #Formula
#Formula(value = "SELECT count(*) as checker FROM fb_user_favorites WHERE cat_id = 34699 AND user_id = '52') ")
#Transient
private String checker;
#Transient is part of JPA spec. In Hibernate fields marked with this annotation just simply ignored/excluded from any JPA engine/runtime logic.
#Formula is part of Hibernate. Fields, marked with it, don't persisted by Hibernate (first argument do not use #Transient as redundant), values are calculated by provided SQL when executing query for entity.
So for Hibernate to see this fields, they should not be excluded by #Transient
TL;DR remove #Transient annotation
Complicated but fast working way.
Adding isFavorite field to the entity:
#Transient
private boolean isFavorite;
Create an entity linking Product and User:
public class ProductFavorite {
#Id
#GeneratedValue(strategy = IDENTITY)
private Long id;
#ManyToOne(optional = false, fetch = LAZY)
private Product product;
#ManyToOne(optional = false, fetch = LAZY)
private User user;
}
Then create a repository with a method to find the user's favorite products:
#Repository
public interface ProductLikeRepository extends JpaRepository<ProductFavorite, Long> {
#Query("select f.product.id from ProductFavorite f where f.product in ?1 and f.user = ?2")
Set<Integer> findProductIdsByIdsAndUser(List<Product> products, User user);
}
And at the end, write a method that will fill in the isFavorite field:
public void fillFavorite(List<Product> products, User user) {
if (products.isEmpty()) {
return;
}
var likedIds = favoriteRepository.findProductIdsByIdsAndUser(products, user);
for (Product product : products) {
product.setFavorite(likedIds.contains(product.getId()));
}
}
You need to call it manually:
List<Product> products = productRepository.findAll();
fillFavorite(products, currentUser());

JPA - deleteBy query not working, orphanRemoval=true not working

I am unable to understand why JPA delete is not working. Here is my parent entity:
public class RoleEntity {
//...other attributes like name etc.
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
#JoinColumn(name = "role_id", referencedColumnName = "id", nullable = false, insertable = false, updatable = false)
private Set<RoleExtEntity> extensions;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "file_id", referencedColumnName = "id", nullable = false)
private FileEntity fileEntity;
}
RoleRepository:
#Repository
public interface RoleRepository extends JpaRepository<RoleEntity, Long> {
#Transactional
int deleteByFileEntityAndName(FileEntity fileEntity, String roleName);
}
I am trying to delete the RoleEntity using FileEntity and RoleName attributes. The delete query returns val = 1 however when I do a findBy again, it gives me the record instead of null (as I think the record should be deleted, both parent and child should be deleted).
FileEntity fileEntity = fileRepository.findByFolderId(id);
RoleEntity roleToBeDeleted = roleRepository.findByFileEntityAndName(fileEntity, roleName);
int val = roleRepository.deleteByFileEntityAndName(fileEntity, roleName);
RoleEntity doesroleExistEntity = roleRepository.findByFileEntityAndName(fileEntity, roleName);
I have tried out various solutions mentioned on this platform like by using:
orphanRemoval = true
#Transactional annotation
flush()
CascadeType.ALL
However, they don't seem to work. Can someone please let me know what I am doing incorrectly here? Thanks!
Update: The issue was that I was calling a wrong method from a persistence service in my code. That method was a readOnlyTransaction() which didn't allow me to do the delete so I had to use another method withTransaction() that solved my issue.
Other database query is logged when you call I think service method?
Yot call the jpa delete method.
JPA Method roleRepository.findByFileEntityAndName(fileEntity, roleName);
return something maybe try show check.

Hibernate mapping user relation to entities

Let's se we have Hibernate entity User with basic fields such as username, password, roles etc..
Now we have an entity such as Car.
User has a OneToOne relationship with Car, cause he can own a car. But he also has besides this a OneToMany relationship to Car, because he also owns the cars of his children. But in the frontend I want to know which cars he owns for himself and which cars he owns for his children. The same applies to the relationship between User and motorbike (his own, his childrens, etc...)
How would the User entity class look like? Is it good to have the relationships mapped in an "Helper" entity such as UserData:
#Entity
#Data
#Table( name = "users",
uniqueConstraints = {
#UniqueConstraint(columnNames = "username")
})
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Size(max = 150)
private String username;
#NotBlank
#Size(max = 120)
private String password;
#OneToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_DATA_ID")
private UserData userData;
UserData:
#Entity
#Data
#Table( name = "user_data")
public class UserData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinColumn(name = "OWN_CAR_ID")
private Car ownCar;
#OneToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinColumn(name = "PARTNER_CAR_ID")
private Car partnerCar;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable( name = "user_children_cars",
joinColumns = #JoinColumn(name = "user_data_id"),
inverseJoinColumns = #JoinColumn(name = "car_id"))
private Set<Car> childrenCars = new HashSet<>();
public boolean addToChildrenCarSet(Car c) {
return childrenCars.add(c);
}
public UserData() {
}
}
As you ask for an opinion, I would say it gets unnecessary complicated if you use the intermediate entity user_data. :-) There is no real drawback to add more fields and keys into the user class - performance is probably also better then using the EAGER fetching. If performance is an issue, better optimize querys later on then splitting the table now.
Also the #ManyToMany I would avoid - better create the intermediate table and relations yourself. You can check out https://bootify.io and create your database schema there. There is no EAGER fetching and also no CascadeType.ALL (both only good ideas in special cases), you would probably add more problems with that then actual helping in any way.
So the addToChildrenCarSet method would end up in a #Service class, in a method with #Transactional, in my proposal.

spring one-to-may annotation exception

I'm using spring-boot.
I have a class named Datum and a class named User. A user can have many datum. So the relation is one-to-many from user's perspective. Now I want to design those classes.
Here is what I have tried :
public class Datum{
...
#OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
private User user;
...
}
And :
public class User{
...
#OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
Set<Datum> data = new HashSet<>();//i have tried list-arrayList too
...
}
But this gives me org.hibernate.AnnotationException: Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements: error.
What are wrong here?
public class Datum{
...
#OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
private User user;
...
}
This is not a OneToMany relationship. This is a ManyToOne, by looking at your User class.
This will do the job:
public class Datum {
...
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private User user;
...
}
As a user can have many datum, so in user class relation will be like
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private List<Datum> datums = new ArrayList<>()
And in Datum class no relation is needed.
The One to Many relationship is a Many to One on the other side. You should map it in this way:
public class Datum{
...
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
...
}
And:
public class User{
...
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private Set<Datum> data = new HashSet<>();
...
}
As you can see, the relation is a Many to One on the Datum side. Furthermore it should have a FetchType.LAZY to increase performance and, if can't be a Datum without user, you should also ad "orphanRemoval = true".

JPA Specification - search simultaneously in main table rows and child rows with relation OneToMany

I have two entities. One of them is a child of the other one with a relation with OneToMany. Is it possible to implement search criteria that looks up simultaneously in both the main entity and all the child entities?
Example: I have a Company with many employees. If I search with some text, I want to retrieve all the companies, which title contains that text or its employee's names contain that text.
Here are the example entities:
#Entity
public class Company extends AbstractEntity {
#Column(nullable = false, unique = true)
private String uuid;
#Column(nullable = false)
private String companyName;
#OneToMany(mappedBy = “company”, cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
protected Set<Employee> employees = new HashSet<>();
}
#Entity
public class Employee extends AbstractEntity {
#Column(nullable = false, unique = true)
private String uuid;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = “company_id”, nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private Company company;
}
Here is the example query, that I want to transform into Specification criteria
#Query(value = “SELECT DISTINCT c from Company c left outer join c.employees e
WHERE c.companyName LIKE CONCAT('%',:text,'%')
or e.firstName LIKE CONCAT('%',:text,'%')
or e.lastName LIKE CONCAT('%',:text,'%')”)
If you are using Spring JPA data repository, your interface method would look like this.
Company findByCompanyNameConatainingOrEmployeesFirstNameConatainingOrEmployeeslastNameConataining(String searchTextCompanyTitle, String searchTextEmployeeFName, String searchTextEmployeeLName);
If you are not using data repository, please explain your data access design to get an accurate answer.

Resources