How add where condition in fillAll method in spring boot using hibernate - java

I am using Spring boot framework with hibernate. I want to show all data from database only certain conditions. Here is my query
SELECT * FROM `client_master` WHERE CLIENT_GROUP='S'
I want to get data which CLIENT_GROUP data has only S. I have used bellow cod for spring boot..
Model I have used bellow code..
#Entity
#Table(name = "client_master")
public class ClientMasterModel {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name= "ID")
private int ID;
#Column(name= "NAME")
private String name;
//getter or setter
}
My repository is bellow
public interface Staff_Add_Repository extends JpaRepository<ClientMasterModel, Long> {
}
In service, I have used bellow code..
#Autowired
Staff_Add_Repository add_Repository;
public List<ClientMasterModel> findAll(){
return add_Repository.findAll();
}
Above method returns all data. I want to get only specific data .
How to do it? Please help me..

Try
List<ClientMasterModel> findByClientGroup(String clientGroup);

Assuming you have a field named clientGroup in your ClientMasterModel you just need a correctly named method and possibly - if you wish - a default wrapper method in your repository as following:
public interface Staff_Add_Repository
extends JpaRepository<ClientMasterModel, Long> {
List<ClientMasterModel> findByClientGroup(String clientGroup);
default List<ClientMasterModel> findWhereClientGroupIsS() {
return findByClientGroup("S");
}
}
Also the findAllBy is a synonym to findBy. See this question

Related

How can I write SQL query in JPA repository with Spring Boot?

I'm doing a spring boot experiment and using MySQL.
For example, if I have a list of users, but I want to get the specified names, how can I write the SQL query that only indicates this situation?
This is my model class :
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
#Column(name="first_name")
public String name;
#Column (name="last_name")
public String last_name;
}
This is my JPA interface :
public interface CommentRepository extends JpaRepository<User , Long >{
// All C.R.U.D database methods
}
Finally, my controller area is as below :
#RestController
#RequestMapping(path="/api/v1/users")
public class CommentController {
#Autowired
CommentRepository repository ;
#GetMapping(path="/list")
public List<User> users() {
return repository.findAll();
}
}
Maybe you didn't understand my problem, I just want to write a customizable query of my own.
For example, I want to pull the data with the method I designed, while I normally pull the data by numbers with the find by id method.
You can either use methods that will be translated into queries or write your queries in the #Query annotation.
Please read the docs: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories

JPA MappedSuperClass common audit value for all entities

I have several JPA entities, each Entity has a database user column, in that column I have to store the user that makes changes to a specific row in the table.
I created a 'MappedSuperclass' Bean that all the entities would extend from, this is the MappedSuperclass.
#MappedSuperclass
public abstract class AuditableBean {
#Column(name = "modifier_user", nullable = false)
private String modifier_user;
// Getters and Setters
}
This is one Entity that extends from the 'MappedSuperclass'.
#Entity
#Table(name = "nm_area_ref")
public class ServingAreaReferenceBean extends AuditableBean {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "nm_area_ref_id")
private UUID id;
#Column(name = "nm_srv_area_desc", nullable = false)
private String description;
#Column(name = "nm_retired", nullable = false)
private boolean retired;
// Getters and Setters
}
And, all the Beans has a corresponding service method used to save the data on the database, this is one of the services class (each service injects a repository for CRUD operations).
// Service
#Component
public class ServingAreaReferenceBO {
#Inject private ServingAreaReferenceRepository repository; //repository injection
#Inject private CloudContextProvider cloudContextProvider;
public List<ServingAreaReferenceBean> getAllServingAreaReferences() {
return Lists.newArrayList(repository.findAll());
}
public Optional<ServingAreaReferenceBean> findById(UUID id) {
return repository.findById(id);
}
public ServingAreaReferenceBean create(ServingAreaReferenceBean servingAreaReference) {
Optional<CloudContext> cloudContext = Optional.ofNullable(cloudContextProvider.get());// line 1
servingAreaReference.setUpdaterUser(cloudContext.map(CloudContext::getUserId).orElse(null));// line 2
return repository.save(servingAreaReference);// line 3
}
}
// Repository - It extends from CrudRepository (insert, update, delete operations)
#Repository
public interface ServingAreaReferenceRepository extends CrudRepository<ServingAreaReferenceBean, UUID> {
boolean existsByDescription(String description);
boolean existsByDescriptionAndIdIsNot(String description, UUID id);
}
When 'repository.save()' (line 3) executes, It stores the user successfully, but I put the user logic just before executing the save method (lines 1, 2). So I don't think that repeating those two lines on each service would be the best approach, instead, I'd like to implement a generic method or a generic class that sets the user for all the Bean Entities before executing the save method.
Is that possible? what is the better approach for that?
I was thinking to implement something like this, but not sure how to make it generic?
#Component
public class AuditableBeanHandler {
#Inject private CloudContextProvider cloudContextProvider;
public AuditableBean populateAuditInformation(AuditableBean auditableBean) {
Optional<CloudContext> cloudContext = Optional.ofNullable(CloudContextProvider.get());
auditableBean.setUpdaterUser(CloudContext.map(cloudContext::getUserId).orElse(null));
return auditableBean;
}
}
Well what I understood, you have to set user before each save call of an entities :
This can be solved by using a well known design pattern called "Template method design pattern".
Just create a parent class for service class :
public abstract class AbstractService<T extends AuditableBean> {
public AuditableBean populateAuditInformation(AuditableBean auditableBean) {
Optional<CloudContext> cloudContext = Optional.ofNullable(CloudContextProvider.get());
auditableBean.setLastUpdatedByUser(CloudContext.map(cloudContext::getUserId).orElse(null));
return auditableBean;
}
public absract T save(T areaReference);
public final T create(T t) {
t = populateAuditInformation(t);
return save(t);
}
And in your service class extends this abstract service and add save method:
public class AreaReferenceService extends AbstractService<AreaReferenceBean> {
public AreaReferenceBean save(AreaReferenceBean AreaReference) {
return repository.save(AreaReference);
}
}
While calling service method, call create() method.
hope this will solve your problem, and also you can read more about Template method design pattern.
I think you're pretty close with the AuditableBean.
Add the following configuration to enable auditing:
// Annotate a configuration class with this
#EnableJpaAuditing(auditorAwareRef = "auditAware")
Add this "auditAware" bean, you'll want to tweak it to match whatever auth mechanism you're using. It's sole purpose is to return the username of the authenticated user, Spring will use this.
#Bean
public AuditorAware<String> auditAware() {
return () -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return Optional.of(authentication.getPrincipal());
};
}
Add one more annotation to your modified_user field (#LastModifiedBy). This tells Spring that when an update occurs on the entity, set this field to the value returned from your AuditAware bean.
#Column(name = "modifier_user", nullable = false)
#LastModifiedBy
private String modifier_user;
See the Spring Data JPA Documentation for more information on the available audit fields.

How do I populate two fields of entity using Hibernate?

I am building an API to return two fields as such:
{
currentPoints: 325,
badgeName: "Some Badge"
}
However, I am having trouble using hibernate in order populate those two fields. I made two attempts and both are throwing errors. Both of these errors can be found in their respective Repository file. In the 2nd attempt, I am using native=true and am able to get it to work using a SELECT *. However, I am trying to only populate and return two fields of the entity.
One solution I thought about is using the 2nd approach with a SELECT * and creating another package named response with CurrentInfoResponse class and just returning that class. However, I wanted to see if there was a way to avoid this using the current model that I have.
Possible Solution:
#Getter
#AllArgsConstructor
public class CurrentInfoResponse{
private Integer currentPoints;
private String badgeName
}
Package Structure:
Controller.java:
#GetMapping("/current-badge/{userId}")
public CurrentBadgeInfoModel getCurrentBadge(#PathVariable Integer userId){
return currentBadgeInfoService.getCurrentBadge(userId);
}
ServiceImpl.java:
#Override
public CurrentBadgeInfoModel getCurrentBadge(Integer userId){
return currentBadgeInfoRepository.getCurrentBadge(userId);
}
CurrentBadgeInfoModel.java:
#Getter
#Entity
#Table(name = "user_current_badge_info")
public class CurrentBadgeInfoModel {
#Id
#Column(name = "user_current_info_id")
private Integer userCurrentBadgeInfo;
#Column(name = "user_id")
private Integer userId;
#Column(name = "current_points")
private Integer currentPoints;
#ManyToOne
#JoinColumn(name = "badge_id")
private BadgeModel badgeModel;
}
BadgeModel.java
#Getter
#Entity
#Table(name = "badge_info")
public class BadgeModel {
#Id
#JoinColumn(name= "badge_id")
private Integer badgeId;
#Column(name = "badge_name")
private String badgeName;
}
Repository.java - ATTEMPT 1:
#Repository
public interface CurrentBadgeInfoRepository extends JpaRepository<CurrentBadgeInfoModel, Integer> {
#Query("SELECT cbim.currentPoints, cbim.badgeModel.badgeName FROM CurrentBadgeInfoModel cbim JOIN
cbim.badgeModel WHERE cbim.userId=?1")
CurrentBadgeInfoModel getCurrentBadge(Integer userId);
}
//Error: No converter found capable of converting from type [java.lang.Integer] to type [com.timelogger.model.CurrentBadgeInfoModel]
Repository.java - ATTEMPT 2:
#Repository
public interface CurrentBadgeInfoRepository extends JpaRepository<CurrentBadgeInfoModel, Integer> {
#Query(value = "SELECT current_points, badge_name FROM user_current_badge_info ucbi JOIN badge_info bi ON ucbi.badge_id=bi.badge_id WHERE user_id=?1", nativeQuery = true)
CurrentBadgeInfoModel getCurrentBadge(Integer userId);
}
//Error: Column 'user_current_info_id' not found
Using the SELECT clause of HQL should help you here.
If you don't have that constructor, you can add it
#Query("SELECT new CurrentBadgeInfoModel(cbim.currentPoints, cbim.badgeModel.badgeName) FROM CurrentBadgeInfoModel cbim JOIN
cbim.badgeModel WHERE cbim.userId=?1")
Notice the usage of new CurrentBadgeInfoModel(cbim.currentPoints, cbim.badgeModel.badgeName)
I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(CurrentBadgeInfoModel.class)
public interface CurrentInfoResponse {
Integer getCurrentPoints();
#Mapping("badgeModel.badgeName")
String getBadgeName();
}
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
CurrentInfoResponse findByUserId(Integer userId);
The best part is, it will only fetch the state that is actually necessary!

Update or saveorUpdate in CRUDRepository

I know there's already a similar question answered previously, but my problem is implementing save with update while there are 3 methods in the interface.
I'm currently using the following methods in my project and don't know how to make saveOrUpdate in this.
The following are my classes:
public interface CompanyRepository extends CrudRepository<Company,Long>{
Company findByCompanyName (String companyName);
List<Company> findAll();
Company findById(Long id);
}
The following is part of my Company Class
#Entity
public class Company extends BaseEntity{
#NotNull
#Size(min = 2, max = 16)
private String companyName;
#Length(max = 60)
private String desc;
//TODO max: add LOGO class later for pic saving
#OneToMany
private List<MobileModel> mobileModels;
public Company()
{
super();
mobileModels = new ArrayList<>();
}
//Getters n setters
}
The following is my baseEntity clas
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected final Long id;
#Version
private Long version;
//Getters n setters
}
Thanks in advance.
I read everywhere and tried so many things for 5 hours.
I just want CompanyRepository to implement all 3 methods without me overriding them in some other class but if I have too then explain how because part of my code is dependent on CompanyRepository. I just wish to add save with update, please explain with respect to my code.
CrudRepository has only save but it acts as update as well.
When you do save on entity with empty id it will do a save.
When you do save on entity with existing id it will do an update that means that after you used findById for example and changed something in your object, you can call save on this object and it will actually do an update because after findById you get an object with populated id that exist in your DB.
save in CrudRepository can accept a single entity or Iterable of your entity type.
putting below if check resolve my issue and save method is working as save and update both when i pass id it updates the record in database and when i dont pass id it save new record in database
place is incoming object in my case and new place is new object of place in which i am setting the place id
if(place.getPlaceId()!=0)
newPlace.setPlaceId(place.getPlaceId());

#Indexed on nested property not working in Spring-data for mongo

I have the following object structure:
#Document(collection = "user")
#TypeAlias("user")
public class User {
#Id
private ObjectId id;
private Contact info = new Contact();
}
and here is the Contact pojo:
public class Contact {
#Indexed(unique = true)
private String mail;
}
But for some reasons not known to me, I don't see Spring-data creating a unique index for the property info.mail
To summarize, I have this json structure of user object:
{_id:xxxxx,info:{mail:"abc#xyz.shoes"}}
And I want to create a unique index on info.mail using Spring data with the above pojo structure. Please help.
As far as I remember, annotating embedded fields with #Indexed will not work. #CompoundIndex is the way to go:
#Document(collection = "user")
#TypeAlias("user")
#CompoundIndexes({
#CompoundIndex(name = "contact_email", def = "{ 'contact.mail': 1 }", unique = true)
})
public class User {
#Id
private ObjectId id;
private Contact info = new Contact();
}
In my case I had a fresh spring boot application 2.3.0 with just #Document, #Id and #Indexed annotations. I was able to retrieve and insert documents but it refused to create the index other than the PK. Finally I figured that there is a property that you need to enable.
spring.data.mongodb.auto-index-creation = true
As a matter of fact it even works on nested objects without #Document annotation.
Hope this helps :)
Obsolete answer, this was with and older version of mongodb 1.x.
Had the same issue, it seems that your Contact class is missing the #Document annotation i.e.
#Document
public class Contact {
#Indexed(unique = true)
private String mail;
}
Should work, quote from the spring mongodb reference
Automatic index creation is only done for types annotated with #Document.
Extending #Xenobius's answer:
If any configuration extending AbstractMongoClientConfiguration is set, MongoMappingContext will back off. The result is:
spring.data.mongodb.auto-index-creation = true will not be effective
You will need add this into your own configuration:
#Override
protected boolean autoIndexCreation() {
return true;
}
ref: https://github.com/spring-projects/spring-boot/issues/28478#issuecomment-954627106

Categories