Model mapper not mapping values - spring-boot

I am mapping a collection with a collection.Its getting mapped successfully most of time but sometime its getting failed and i am getting null values.
ArrayList<RiskRequestDTO> riskList = new ArrayList<>();
Iterable<Risk> risks = RiskRepository.findAll();
if (risks != null) {
java.lang.reflect.Type targetListType = new TypeToken<List<riskRequestDTO>>() {
}.getType();
riskList = modelMapper.map(risks, targetListType);
}
Risk DTO
i am facing some issue to add complete code so i removed setters and getters.I am confirming that the relevant annotations are present with setters and getters
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"riskId", "localeTranslations", "lastModifiedAt", "lastModifiedBy"
})
public class RiskRequestDTO {
#JsonProperty("riskId")
private int riskId;
#JsonProperty("localeTranslations")
private Set<LocaleTranslation> localeTranslations;
#JsonProperty("lastModifiedAt")
private Date lastModifiedAt;
#JsonProperty("lastModifiedBy")
private UserViewDTO lastModifiedBy;
Risk Model
I am facing some issue to add complete code so i removed setters and getters of these entity
#Entity
#Table(name = "risk")
public class Risk {
/**
* risk_id , primary key.
*/
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = “risk_id")
private int riskId;
/**
* last modified date.
*/
#Column(name = "last_modified_at")
private Date lastModifiedAt;
/**
* details of locale.
*/
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name="risk_to_local_translation", joinColumns={ #JoinColumn(name="risk_id") }, inverseJoinColumns={ #JoinColumn(name="locale_translation_id") })
private Set<LocaleTranslation> localeTranslations;
/**
* details of the user who updated the recommendations.
*/
#ManyToOne( fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "last_modified_by", nullable = false)
private User lastModifiedBy;
I have updated question with DTO and Entity model

Related

Spring boot JPA persist manytomany unidirectionnal relationship

I have a Spring Boot project (with JHipster) with 2 JPA Entities : User and Film.
I've created an unidirectionnal ManyToMany relationship between them.
User is the owner of the relationship.
I would like to add films into favorite list of films of user (property 'favorites' in User entity).
But when I try to add a film into favorites list, nothing is persisted into table 'user_film_favorite' (join table between the 2 entities).
The mapping seems ok because when I manually enter data in this join table, I'm able to retrieve the list of films for a user.
I've looked for a lot of similar issues here but can't find where the problem is.
Entity User :
#Entity
#Table(name = "jhi_user")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class User extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Other properties
#ManyToMany(cascade = CascadeType.PERSIST)
#JoinTable(
name = "user_film_favorite",
joinColumns = { #JoinColumn(name = "user_id", referencedColumnName = "id") },
inverseJoinColumns = { #JoinColumn(name = "movie_id", referencedColumnName = "id") }
)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#BatchSize(size = 20)
private List<Film> favorites = new ArrayList<>();
Entity Film :
#Entity
#Table(name = "film")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Film implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#NotNull
#Column(name = "title", nullable = false)
private String title;
#Column(name = "plot")
private String plot;
#Column(name = "rating")
private Float rating;
FilmService :
/**
* Add one film to current user favorites.
*
* #param id the id of the film.
* #return the film saved into user favorites.
*/
#Transactional(readOnly = true)
public Optional<FilmDTO> addToFavorites(Long id) {
log.debug("Request to get Film : {}", id);
Optional<Film> filmOpt = filmRepository.findById(id);
// Get current logged user with his favorites
Optional<User> userOpt = userService.getUserWithFavorites();
if (filmOpt.isPresent() && userOpt.isPresent()) {
User user = userOpt.get();
user.getFavorites().add(filmOpt.get());
userService.save(user);
}
return filmOpt.map(filmMapper::toDto);
}
UserService :
/**
* Save a user.
*
* #param user the entity to save.
* #return the persisted entity.
*/
public User save(User user) {
log.debug("Request to save User : {}", user);
return userRepository.save(user);
}
If anyone could help me that would be really cool ! Thanks in advance :)
You are reading the User from the database so calling save will call EntityManger.merge. Therefor you also need to add
CascadeType.MERGE
to the ManyToMany mapping.

Spring Data Projection with OneToMany error

I have a entity call Circuit.
#Entity
public class Circuit implements Comparable<Circuit>, Serializable {
#Column
private String id;
#OneToMany(mappedBy = "circuit", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<Step> workflow = new HashSet<>();
...
}
I have a class called CircuitLight
public class CircuitLight {
private String id;
private Set<Step> workflow;
/* constructor, getters and setters */
}
In my CircuitRepository, i'm trying to make a projection
#Transactional(readOnly = true)
#Query("select new com.docapost.circuit.CircuitLight(c.id, c.workflow) from Circuit c where c.account.siren = :siren")
Set<CircuitLight> findAllByAccountSirenProjection(#Param("siren") String siren);
When i execute, i have a error message:
could not extract ResultSet; SQL [n/a] com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'circuit0_.id' in 'on clause'
I try with other entity. Every time i have a property with a relation #OneToMany, i have the issue...
Is it possible to make a projection with class (Without use a interface) when there are a relation OneToMany ?
UPDATE:
Step.class
#Entity
public class Step implements Comparable<Step>, Serializable {
private static final List<String> INDEXABLE_PROCESSES = Arrays.asList(
ParapheurWorkflowModel.SERVER,
ParapheurWorkflowModel.SIGN,
ParapheurWorkflowModel.VISA
);
#Id
#GeneratedValue
#Expose
#SerializedName("step_id")
public long id;
#ManyToOne
public Circuit circuit;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(joinColumns = #JoinColumn(name = "step_id"), inverseJoinColumns = #JoinColumn(name = "technicalGroup_id"))
private List<TechnicalGroup> technicalGroups = new ArrayList<>();
#Column(name = "step_type", nullable = false)
#Expose
#SerializedName("subprocess_ref")
public String type;
#Column(nullable = false)
public int orderIndex;
/* contructor, getters and setters */
}
UPDATE 2:
Hum.... My bad, in my circuit class, i have a EmbeddedId
#EmbeddedId
private CircuitPK key;
#Embeddable
public static class CircuitPK implements Serializable {
public String id;
public String siren;
}
I try with this code in Step.class
#ManyToOne
#JoinColumns(value = {
#JoinColumn(name = "circuit_siren", referencedColumnName = "siren"),
#JoinColumn(name = "circuit_id", referencedColumnName = "id")
})
public Circuit circuit;
The result is the same
Write the following code in the Step entity
#ManyToOne
#JoinColumn(name="id", nullable=false)
private Circuit circuit;

Hibernate #OneToMany relation cascade option not working

I design simple 1:N schema , Account(1):AccountProfileImage(N).
Below codes are entity codes.
// Account.java
#Entity
#Table(name = "account")
#Getter
#NoArgsConstructor(access = AccessLevel.PROTECTED)
#EntityListeners(AuditingEntityListener.class)
public class Account {
#GeneratedValue
#Id
#Column(name = "id")
private Long id;
#Column(name = "email", nullable = false)
private String email;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#CreatedDate
#Column(name = "created_at")
private LocalDateTime createdAt;
#OneToMany(mappedBy ="account",cascade = CascadeType.ALL)
private final List<AccountProfileImage> profileImages= new ArrayList<>();
#Builder
public Account(String email,String firstName,String lastName,String password){
this.email=email;
this.firstName=firstName;
this.lastName=lastName;
this.password=password;
}
}
// AccountProfileImage.java
#Entity
#Table(name = "account_profile_image")
#NoArgsConstructor(access = AccessLevel.PROTECTED)
#Getter
#EntityListeners(AuditingEntityListener.class)
public class AccountProfileImage {
#Id
#GeneratedValue
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "account_id")
private Account account;
#Column(name = "image_url")
private String imageURL;
#CreatedDate
#Column(name = "created_at")
private LocalDateTime createdAt;
#Builder
public AccountProfileImage (Account account,String imageURL){
this.account=account;
// this.account.addProfileImage(this);
this.imageURL=imageURL;
}
}
and this is test code for AccountProfileRepository code.
#Test
#Rollback(value = false)
public void saveAccountProfileImageTest() throws Exception {
// given
Account account = Account.builder()
.email("user#email.com")
.firstName("user")
.lastName("user")
.password("1234")
.build();
AccountProfileImage profileImage = AccountProfileImage.builder()
.account(account)
.imageURL("pathToURI")
.build();
AccountProfileImage profileImage2 = AccountProfileImage.builder()
.account(account)
.imageURL("pathToURI2")
.build();
accountRepository.save(account);
// when
List<AccountProfileImage> images = profileImageRepository.findAllByAccount_IdOrderByCreatedAtDesc(1L);
// then
// this assertion fail
assertThat(images.size()).isEqualTo(2);
}
What i want to expect find by List of images whose size is 2 because I add CscadeType.ALL in Account entity class and when creating AccountProfileImage object, I set account member variable in AccountProfileImage object.
this.account=account;
Did I something wrong?
I add below method in Account entity and 2 lines at test code, then it works fine. Do i have to do this everytime? Is there exist another better approach or best practice?
// Account Entity
public void addProfileImages(AccountProfileImage image){
this.profileImages.add(image);
}
// test code
account.addProfileImages(profileImage);
account.addProfileImages(profileImage2);
accountRepository.save(account);
// when
List<AccountProfileImage> images = profileImageRepository.findAllByAccount_IdOrderByCreatedAtDesc(1L);
// then
// this assertion pass
assertThat(images.size()).isEqualTo(2);
In Bi-directional relationships, you have to define the association on both ends of the relationship. To avoid any issues, you can update the helper addProfileImage(..) method to add the AccountProfileImage to the list and set account property of the image to the current account. This is the best practice as this way, the helper method will set up the association across both ends of the bi-directional relationship.
E.g.
public void addProfileImages(AccountProfileImage image){
this.profileImages.add(image); // Add image to profileImages
image.setAccount(this); // Set account property to the current account
}
Test:
#Test
#Rollback(value = false)
public void saveAccountProfileImageTest() throws Exception {
// given
Account account = Account.builder()
.email("user#email.com")
.firstName("user")
.lastName("user")
.password("1234")
.build();
AccountProfileImage profileImage = AccountProfileImage.builder()
.imageURL("pathToURI")
.build();
AccountProfileImage profileImage2 = AccountProfileImage.builder()
.imageURL("pathToURI2")
.build();
// Setup association
account.addProfileImage(profileImage);
account.addProfileImage(profileImage2);
accountRepository.save(account);
// when
List<AccountProfileImage> images = profileImageRepository.findAllByAccount_IdOrderByCreatedAtDesc(1L);
// then
// this assertion fail
assertThat(images.size()).isEqualTo(2);
}

Hibernate - Spring - ConstraintViolationException - UniqueConstraint

I'm trying to make some fixtures for my Profile model but every time I'm trying to save it "again" after I did an update, I get this message:
nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
This is my Profile class:
#Entity
#Data
#Builder
#ToString(of = {"birthday", "discordId", "description", "spokenLanguages"})
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "profile", uniqueConstraints = #UniqueConstraint(columnNames = "discordId"))
public class Profile implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idProfile;
private Date birthday;
#Column(name="discordId", insertable=true, updatable=false)
private String discordId;
private String description;
#ElementCollection(fetch = FetchType.EAGER)
private Set<String> spokenLanguages = new LinkedHashSet<String>();
#JsonIgnore
#OneToMany(fetch = FetchType.EAGER)
private Set<ProfileGame> profileGames = new LinkedHashSet<>();
#OneToOne(mappedBy = "profile", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
private User user;
#ManyToOne
private TimeSlot timeSlot;
}
Here is the call:
#Order(7)
#Test
void fillProfileGame() {
List<Profile> profileList = this.profileRepository.findAll();
for (Profile profile : profileList) {
List<Game> gameList = this.gameRepository.findAll();
Collections.shuffle(gameList);
int rndNbGame = new Random().ints(1, 5).findFirst().getAsInt();
for (int i = 1; i <= rndNbGame; i++) {
int rndLevel = new Random().ints(1, 100).findFirst().getAsInt();
int rndRanking = new Random().ints(1, 3000).findFirst().getAsInt();
Game rndGame = gameList.get(0);
gameList.remove(0);
ProfileGame profileGames = new ProfileGame(profile, rndGame, "level-" + rndLevel,
"ranking-" + rndRanking);
this.profileGameRepository.save(profileGames);
this.gameRepository.save(rndGame);
}
this.profileRepository.save(profile);
}
}
So what I understand is that Hibernate won't let me update this object because it has a unique contraint field ?
How do we proceed when we want a field to be unique and still being able to update other fields ?
From the code snippet, what I see is that there are some unique constraints applied on the column 'discordId'.
#Table(name = "profile", uniqueConstraints = #UniqueConstraint(columnNames = "discordId"))
and
#Column(name="discordId", insertable=true, updatable=false)
private String discordId;
As you can see, there is a parameter 'updatable' which is set to false. Therefore, when you are trying to update an already existing object, hibernate is throwing UniqueConstraintViolationException.
To fix this, set 'updatable=true' or remove it altogether and it should work fine.
#Column(name="discordId", insertable=true, updatable=true)
private String discordId;

HIbernate + JPA OneToMany Lazy loading not working if no foreign key specified in the db

Hibernate lazy loading is not working in my code. It loads the entire data even it is specified as FetchType LAZY
#Transactional(propagation = Propagation.NEVER)
public OrderItem getItem(String itemId) throws Exception {
OrderItem item = itemDao.find(OrderItem.class, Integer.parseInt(itemId));
if (item == null) {
throw new Exception(502, "We are unable to load item for #" + itemId);
}
return item;
}
#NotFound(action = NotFoundAction.IGNORE)
#OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
#JoinColumn(name = "id_order_detail")
#Fetch(value= FetchMode.JOIN)
#JsonManagedReference
private Set<OrderItemStateChangeEntry> itemStateHistory;
I could not able to lazy load the contents. There is no foreign key constraint set in the db. And its not possible to set as the many parent data not present in the system.
Can somebody help me on this
Update
Added my class and reference. But lazy load work
#Entity
#Table(name = "ps_orders")
#AttributeOverrides({
#AttributeOverride(name="id",column=#Column(name="id_order")),
#AttributeOverride(name="createTime",column=#Column(name="date_add")),
#AttributeOverride(name="updateTime",column=#Column(name="date_upd"))
})
public class Order extends BaseEntity{
#Column(name = "id_carrier")
private Integer carrier = 0;
#NotFound(action = NotFoundAction.IGNORE)
#OneToMany(fetch = FetchType.LAZY,cascade={CascadeType.PERSIST, CascadeType.MERGE}, mappedBy="order")
#Fetch(FetchMode.SELECT)
#JsonManagedReference
private Set<OrderStateChangeEntry> orderHistory;
//Getters and Setters
}
#Entity
#Table(name = "ps_order_history")
#EnableBouncerProfile
public class OrderStateChangeEntry implements java.io.Serializable{
public OrderStateChangeEntry(){}
public OrderStateChangeEntry(Order order){
this.order = order;
}
#Id
#Column(name = "id_order_history")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="id_order", nullable=false)
#JsonBackReference
private Order order;
//Getters and Setters
}
It is because of your
#Fetch(value= FetchMode.JOIN)
it disables the lazy loading ...
As you specify the fetch mode in your #OnetoMany relationship, i would say that you can simply remove that line above.

Resources