简体   繁体   中英

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 forBlaze-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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM