I work on a Java Spring boot app where I get the error of Hot-swap failed and schema change is not implemented and the operation is not supported by the VM. Afterward, the table is truncated and have no data at all.
I have 2 models provided below,
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
#NotNull
#NotEmpty
private String name;
#Column(name = "countryName")
#NotNull
#NotEmpty
private String countryName;
#Column(name = "currencyName")
#NotNull
#NotEmpty
private String currencyName;
/*
* total steps is for the keepign the history of the user movement
* */
#Column(name = "totalSteps")
#Min(value = 0L, message = "The value must be positive")
private int totalSteps;
/*
* current steps is for providing the user reward. We will need to set
* it to zero after processing the user payment
* */
#Column(name = "currentSteps")
#Min(value = 0L, message = "The value must be positive")
private int currentSteps;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<RewardList> rewardLists = new ArrayList<>();
public User() {
}
public User(#NotNull #NotEmpty String name, #NotNull #NotEmpty String countryName) {
this.name = name;
this.countryName = countryName;
}
public User(#NotNull #NotEmpty String name, #NotNull #NotEmpty String countryName, #Min(value = 0L, message = "The value must be positive") int totalSteps) {
this.name = name;
this.countryName = countryName;
this.totalSteps = totalSteps;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountryName() {
return countryName;
}
public String getCurrencyName() {
return currencyName;
}
public void setCurrencyName(String currencyName) {
this.currencyName = currencyName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
public int getTotalSteps() {
return totalSteps;
}
public void setTotalSteps(int totalSteps) {
this.totalSteps = totalSteps;
}
public int getCurrentSteps() {
return currentSteps;
}
public void setCurrentSteps(int currentSteps) {
this.currentSteps = currentSteps;
}
public List<RewardList> getRewardLists() {
return rewardLists;
}
public void setRewardLists(RewardList rl) {
this.rewardLists.add(rl);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return getTotalSteps() == user.getTotalSteps() &&
getCurrentSteps() == user.getCurrentSteps() &&
getId().equals(user.getId()) &&
getName().equals(user.getName()) &&
getCountryName().equals(user.getCountryName()) &&
getRewardLists().equals(user.getRewardLists());
}
#Override
public int hashCode() {
return Objects.hash(getId(), getName(), getCountryName(), getTotalSteps(), getCurrentSteps(), getRewardLists());
}
#Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", countryName='" + countryName + '\'' +
", totalSteps=" + totalSteps +
", currentSteps=" + currentSteps +
'}';
}
}
#Entity
public class RewardList {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "reward")
#Min(value = 0L, message = "The value must be positive")
private double reward;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
private User user;
public RewardList() {
}
public RewardList(User user) {
this.user = user;
}
public RewardList(#Min(value = 0L, message = "The value must be positive") double reward) {
this.reward = reward;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public double getReward() {
return reward;
}
public void setReward(double reward) {
this.reward = reward;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RewardList)) return false;
RewardList list = (RewardList) o;
return Double.compare(list.getReward(), getReward()) == 0 &&
getId().equals(list.getId()) &&
getUser().equals(list.getUser());
}
#Override
public int hashCode() {
return Objects.hash(getId(), getReward(), getUser());
}
#Override
public String toString() {
return "RewardList{" +
"id=" + id +
", reward=" + reward +
", user=" + user +
'}';
}
}
The end-point where I have this issue provided below,
// $ curl -X PUT http://localhost:8080/api/v1/users/calculateReward?userId=1 | jq
#PutMapping("/calculateReward")
public ResponseEntity<Object> calculateReward(#RequestParam("userId") Long userId) {
Optional<User> optional = userService.findById(userId);
if (!optional.isPresent()) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
User user = optional.get();
double reward = user.getCurrentSteps() * Parameters.REWARD_PER_STEPS_EUR;
RewardList list = new RewardList();
list.setUser(user);
list.setReward(reward);
rewardListService.save(list);
user.setCurrentSteps(0);
user.setRewardLists(list);
userService.save(user);
JSONObject json = new JSONObject();
double convertionRateToEuro = currencyMap.get(user.getCurrencyName());
double rewardConverted = reward * convertionRateToEuro;
json.put("name", user.getName());
json.put("currency", user.getCurrencyName());
json.put("reward", rewardConverted);
return ResponseEntity.status(HttpStatus.CREATED).body(json);
}
Does anyone know what is going on and can provide a solution?
Thank you.
I find the reason and below I provide a solution. We will need to save the models based on the hierarchy. HotSwap doesn't support adding methods or hierarchy changes as indicated by the error messages. It's the limitation of Java HotSwap, not IntelliJ IDEA. The proper way of code sequence will be,
User user = optional.get();
RewardList list = new RewardList();
list.setUser(user);
list.setReward(reward);
user.setCurrentSteps(0);
user.setRewardLists(list);
// first save the User
userService.save(user);
// Then, save the RewardList as it has one to many relations
rewardListService.save(list);
Related
I am creating a REST API using Spring Boot and for my update method I try to map a DTO Object to a domain one:
public ItemDTO updateItem(Long departmentId, Long itemId, ItemDTO itemDTO) throws ApiException {
Department department = departmentRepository.findById(departmentId).orElseThrow(
() -> new ApiException("Department with this id does not exist ",
HttpStatus.NOT_FOUND));
Item foundItem = validateItem(itemId);
Item convertedItem = mapper.convertToType(itemDTO, Item.class);
if (convertedItem.getStock() < 0) {
throw new ApiException("Stock must be a positive value", HttpStatus.BAD_REQUEST);
}
if (convertedItem.getStockThreshold() < 0) {
throw new ApiException("Stock threshold must be a positive value", HttpStatus.BAD_REQUEST);
}
itemDTO.setId(itemId);
itemDTO.setDepartment(mapper.convertToType(department, DepartmentDTO.class));
foundItem = mapper.convertToType(itemDTO, Item.class);
itemRepository.save(foundItem);
// ItemDTO returnItem = mapper.convertToType(convertedItem, ItemDTO.class);
logger.info("Updated item");
return itemDTO;
}
And this is my model mapper
#Component
public class Mapper {
private final ModelMapper modelMapper;
private final Logger logger = LoggerFactory.getLogger(ModelMapper.class);
public Mapper(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
public <T> T convertToType(Object source, Class<T> resultClass) {
logger.debug("converted object from " + source.getClass().getSimpleName() + " to " + resultClass.getSimpleName());
return modelMapper.map(source, resultClass);
}
}
At this line foundItem = mapper.convertToType(itemDTO, Item.class); it's the problem, before this conversion my foundItem would have a department, after conversion, the department field is null.
Here are my domain and DTO classes
#NoArgsConstructor
#Getter
#Setter
public class DepartmentDTO {
private Long id;
private String description;
private List<Item> items;
public DepartmentDTO(long id, String description) {
this.id = id;
this.description = description;
}
#Override
public String toString() {
return "DepartmentDTO{" +
"id=" + id +
", description='" + description + '\'' +
", items=" + items +
'}';
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DepartmentDTO that = (DepartmentDTO) o;
return Objects.equals(id, that.id) && Objects.equals(description, that.description) && Objects.equals(items, that.items);
}
// #Override
// public int hashCode() {
// return Objects.hash(id, description, items);
// }
}
#NoArgsConstructor
#Entity
#Getter
#Setter
#Table(name = "DEPARTMENTS")
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
#OneToMany(mappedBy = "department", fetch = FetchType.EAGER,
cascade = CascadeType.ALL)
private List<Item> items;
public Department(Long id, String description) {
this.id = id;
this.description = description;
}
#Override
public String toString() {
return "Department{" +
"id=" + id +
", description='" + description + '\'' +
", items=" + items +
'}';
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Department)) return false;
Department that = (Department) o;
return id.equals(that.id) && Objects.equals(description, that.description) && Objects.equals(items, that.items);
}
#Override
public int hashCode() {
return Objects.hash(id, description, items);
}
}
#AllArgsConstructor
#NoArgsConstructor
#Setter
public class ItemDTO {
private Long id;
private String description;
private String price;
private int stock;
private int stockThreshold;
private DepartmentDTO department;
public Long getId() {
return id;
}
public String getDescription() {
return description;
}
public String getPrice() {
return price;
}
public int getStock() {
return stock;
}
public int getStockThreshold() {
return stockThreshold;
}
public Long getDepartment() {
return department.getId();
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ItemDTO itemDTO = (ItemDTO) o;
return stock == itemDTO.stock && stockThreshold == itemDTO.stockThreshold &&
id.equals(itemDTO.id) && description.equals(itemDTO.description) &&
price.equals(itemDTO.price) && department.equals(itemDTO.department);
}
#Override
public int hashCode() {
return Objects.hash(id, description, price, stock);
}
}
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#Entity
#Table(name = "ITEMS")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
private String description;
private String price;
private int stock;
private int stockThreshold = 5;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "department_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Department department;
#Override
public String toString() {
return "Item{" +
"id=" + id +
", description='" + description + '\'' +
", price='" + price + '\'' +
", stock=" + stock +
", department=" + department +
'}';
}
}
I don't understand what kind of mysticism. This method located in class UserService:
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = repository.getByEmail(email.toLowerCase());
if (user == null) {
throw new UsernameNotFoundException("User " + email + " isn't found");
}
AuthorizedUser authorizedUser = new AuthorizedUser(user); // 1
Objects.requireNonNull(authorizedUser); // 2
System.out.println(new AuthorizedUser(user) + " 1"); // 3
int userId = authorizedUser.getId(); // 4
return authorizedUser; // 5
}
In the lines which are numbered in comments,
why does everything go smoothly in line 1-3, line 3 goes to the console:
UserTo{id=100000, name='VadimUserAdmin', email='vadim#gmail.com'} 1
And in line 4, an exception is thrown:
Caused by: java.lang.IllegalArgumentException: Entity must has id
at org.springframework.util.Assert.notNull(Assert.java:201)
at topjava.quest.HasId.id(HasId.java:14)
at topjava.quest.AuthorizedUser.getId(AuthorizedUser.java:22)
at topjava.quest.service.UserService.loadUserByUsername(UserService.java:64)
What should I do with this?
spring.security.version - 5.6.2
hibernate.version - 5.6.5.Final
class AuthorizedUser:
public class AuthorizedUser extends org.springframework.security.core.userdetails.User {
#Serial
private static final long serialVersionUID = 1L;
private UserTo userTo;
public AuthorizedUser(User user) {
super(user.getEmail(), user.getPassword(), true, true, true, true, user.getRoleSet());
setUserTo(Util.userAsTo(user));
}
public int getId() {
return userTo.id();
}
public void setUserTo(UserTo userTo) {
userTo.setPassword(null);
this.userTo = userTo;
}
#Override
public String toString() {
return userTo.toString();
}
}
class UserTo:
public class UserTo extends BaseTo implements Serializable {
#Serial
private static final long serialVersionUID = 1L;
#NotBlank
#Size(min = 2, max = 100)
#ApiModelProperty(example = "New name")
private final String name;
#Email
#NotBlank
#Size(max = 100)
#ApiModelProperty(example = "newmame#gmail.com")
private final String email;
#NotBlank
#Size(min = 6, max = 32)
#ApiModelProperty(example = "newmame123")
private String password;
#ConstructorProperties({"id", "name", "email", "password"})
public UserTo(Integer id, String name, String email, String password) {
super(id);
this.name = name;
this.email = email;
this.password = password;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Override
public String toString() {
return "UserTo{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
'}';
}
}
class BaseTo:
public class BaseTo implements HasId {
#ApiModelProperty(hidden = true)
protected Integer id;
public BaseTo() {
}
public BaseTo(Integer id) {
this.id = id;
}
#Override
public Integer getId() {
return null;
}
#Override
public void setId(Integer id) {
this.id = id;
}
}
class HasId:
public interface HasId {
Integer getId();
void setId(Integer id);
default boolean isNew() {
return getId() == null;
}
default int id() {
Assert.notNull(getId(), "Entity must has id");
return getId();
}
}
What I do wrong?
When you call HasId.id, you call method getId() from BaseTo.class, which returns null. Change the method to
getId(){
return this.id;
}
I'm doing a simple exercise to learn JPA.
When I try to delete an entity of type User, which has a Collection of the other entity Score (annotated with #OneToMany) I get this error:
java.sql.SQLIntegrityConstraintViolationException: Column 'user' cannot be null
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 20 more
These are my classes:
User.java
#Entity
#Table(name = "user")
public class User
{
#Id
private Integer id;
#NotNull
#Size(max = 20)
private String name;
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true)
#JoinColumn(name = "user")
private Collection<Score> scores;
public User() {
}
public User(Integer id, String name, Collection<Score> scores) {
this.id = id;
this.name = name;
this.scores = scores;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<Score> getScores() {
return scores;
}
public void setScores(Collection<Score> scores) {
this.scores = scores;
}
}
Score.java
#Entity
#Table(name = "score")
public class Score
{
#EmbeddedId
private ScoreId id;
#NotNull
private Integer points;
public Score() {
}
public Score(ScoreId id, Integer points) {
this.id = id;
this.points = points;
}
public ScoreId getId() {
return id;
}
public void setId(ScoreId id) {
this.id = id;
}
public Integer getPoints() {
return points;
}
public void setPoints(Integer points) {
this.points = points;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
Score other = (Score) obj;
return Objects.equals(id, other.id) && Objects.equals(points,other.points);
}
return false;
}
#Override
public int hashCode() {
return id!=null ? points!=null ? id.hashCode()+points.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[id =" + id + ",points = " + points;
}
}
ScoreId.java
#Embeddable
public class ScoreId implements Serializable
{
private Integer user;
#Enumerated(EnumType.STRING)
private Game game;
public ScoreId() {
}
public ScoreId(Integer user, Game game) {
this.user = user;
this.game = game;
}
public Integer getUser() {
return user;
}
public void setUser(Integer user) {
this.user = user;
}
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public enum Game
{
HANGMAN,
TRIS
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
ScoreId other = (ScoreId) obj;
return Objects.equals(user,other.user) && game==other.game;
}
return false;
}
#Override
public int hashCode()
{
return user!=null ? game!=null ? user.hashCode()+game.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[user = " + user + ",game = " + game + "]";
}
}
Main.java
public class Main {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("UserJPA");
EntityManager em = factory.createEntityManager();
EntityTransaction et = em.getTransaction();
User demetrio = em.createQuery("SELECT u FROM User u WHERE u.name = 'Demetrio'",User.class).getSingleResult();
et.begin();
em.remove(demetrio);
et.commit();
em.close();
factory.close();
}
}
This is the script to generate db:
CREATE TABLE `user`
(
id INT PRIMARY KEY,
`name` VARCHAR(20) UNIQUE NOT NULL
);
CREATE TABLE score
(
`user` INT,
game ENUM("HANGMAN","TRIS"),
points INT UNSIGNED NOT NULL,
PRIMARY KEY(`user`,game),
FOREIGN KEY (`user`) REFERENCES `user`(id)
ON UPDATE CASCADE
ON DELETE CASCADE
)
I'm using Hibernate as JPA implementation.
I searched for a solution but I did not find anything.
Maybe I'm doing something wrong.
Can you help me?
The implementation I see is absolutly correct, allthou it always can be improoved. The db-design is good. The exception you post can simply not exist but it does. The Database must have a problem. Thats why I asked to post the DDL of the table. I trust in your DDL you posted what makes me think: You did everything right.
What I do is I could only guess.
The table's engine is InnoDB but what is the status of the InnoDB-engine? Is it working? Is it active? Use SHOW ENGINE INNODB STATUS to see the status of InnoDB.
I solved by replacing Integer user of ScoreId with User user with a #ManyToOne annotation.
These are my classes:
User.java
#Entity
#Table(name = "user")
public class User
{
#Id
private Integer id;
#NotNull
#Size(max = 20)
private String name;
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true,mappedBy = "id.user")
private Collection<Score> scores;
public User() {
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<Score> getScores() {
return scores;
}
public void setScores(Collection<Score> scores) {
this.scores = scores;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
User other = (User) obj;
return Objects.equals(id, other.id) && Objects.equals(name, other.name);
}
return false;
}
#Override
public String toString() {
return getClass().getName() + "[id = " + id + ",name = " + name + "]";
}
#Override
public int hashCode() {
return id!=null ? name!=null ? id.hashCode() + name.hashCode() : 0 : 0;
}
}
Score.java
#Entity
#Table(name = "score")
public class Score
{
#EmbeddedId
private ScoreId id;
#NotNull
private Integer points;
public Score() {
}
public Score(ScoreId id, Integer points) {
this.id = id;
this.points = points;
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
Score other = (Score) obj;
return Objects.equals(id,other.id) && Objects.equals(points,other.points);
}
return false;
}
#Override
public int hashCode() {
return id!=null ? points!=null ? id.hashCode()+points.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[id =" + id + ",points = " + points + "]";
}
}
ScoreId.java
#Embeddable
public class ScoreId implements Serializable
{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="user",referencedColumnName = "id")
private User user;
#Enumerated(EnumType.STRING)
private Game game;
public ScoreId() {
}
public ScoreId(User user, Game game) {
this.user = user;
this.game = game;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public enum Game
{
HANGMAN,
TRIS
}
#Override
public boolean equals(Object obj) {
if (obj!=null && getClass()==obj.getClass())
{
ScoreId other = (ScoreId) obj;
return Objects.equals(user,other.user) && game==other.game;
}
return false;
}
#Override
public int hashCode()
{
return user!=null ? game!=null ? user.hashCode()+game.hashCode() : 0 : 0;
}
#Override
public String toString() {
return getClass().getName() + "[user = " + user + ",game = " + game + "]";
}
}
Database schema is the same.
In my case there was an Envers used, and on deleteAll() or delete() it tried to insert a record with type 2 (deleted) into corresponding _aud table.
However, when it does so, all the fields of the record appear to be NULL, but in the _aud table one of the columns was marked as "NON-NULL".
Removing the "NON-NULL" from those column in _aud table fixed the issue.
Using Hibernate 3.6.0
I'm having a real hard time understanding hibernate. I keep running into this issue with lazy initialization exception.
I have an Event entity with a one-to-many relationship with RSVP. When a run a test get back a list of events it works. But when I'm making the call in my controller in order to return it as json, I run into this lazy init error.
This is my event class
#Entity
#Table(name = "EVENT")
public class Event implements Serializable {
#SequenceGenerator(name="event", sequenceName="EVENT_PK_SEQ")
#GeneratedValue(generator="event",strategy=GenerationType.SEQUENCE)
#Id
#Column(name = "EVENT_ID")
private int id;
#Column(name = "DATE_TIME")
private Date date;
#Column(name = "EVENT_NAME")
private String name;
#Column(name = "EVENT_PARTICIPANT_LIMIT")
private int limit;
#Column(name = "EVENT_VISIBILITY")
private boolean visibilty;
#Column(name = "EVENT_LOCATION")
private String location;
#Column(name = "EVENT_DESCRIPTION")
private String description;
#OneToOne(cascade=CascadeType.REMOVE, fetch= FetchType.EAGER)
private User author;
private Date create_date;
#OneToOne(cascade=CascadeType.REMOVE, fetch= FetchType.EAGER)
private EventType eventType;
#OneToOne(cascade=CascadeType.REMOVE, fetch= FetchType.EAGER)
private EventClass eventClass;
#OneToMany(cascade = CascadeType.ALL)
private Set<RSVP> rsvps = new HashSet<RSVP>();
#ManyToMany(mappedBy="event")
private Set<Group> groups = new HashSet<Group>();
public Event(int id, Date date, String name, int limit, boolean visibilty, String location, String description,
User author, Date create_date, EventType eventType, EventClass eventClass) {
super();
this.id = id;
this.date = date;
this.name = name;
this.limit = limit;
this.visibilty = visibilty;
this.location = location;
this.description = description;
this.author = author;
this.create_date = create_date;
this.eventType = eventType;
this.eventClass = eventClass;
}
public Event(){
super();
}
#Override
public String toString() {
return "Event [id=" + id + ", date=" + date + ", name=" + name + ", limit=" + limit + ", visibilty=" + visibilty
+ ", location=" + location + ", description=" + description + ", author=" + author + ", create_date="
+ create_date + ", eventType=" + eventType + ", eventClass=" + eventClass + ", rsvps=" + rsvps
+ ", groups=" + groups + "]";
}
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public boolean isVisibilty() {
return visibilty;
}
public void setVisibilty(boolean visibilty) {
this.visibilty = visibilty;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getCreate_date() {
return create_date;
}
public void setCreate_date(Date create_date) {
this.create_date = create_date;
}
public EventType getEventType() {
return eventType;
}
public void setEventType(EventType eventType) {
this.eventType = eventType;
}
public EventClass getEventClass() {
return eventClass;
}
public void setEventClass(EventClass eventClass) {
this.eventClass = eventClass;
}
public Set<RSVP> getRsvps() {
return rsvps;
}
public void setRsvps(Set<RSVP> rsvps) {
this.rsvps = rsvps;
}
public Set<Group> getGroups() {
return groups;
}
public void setGroups(Set<Group> groups) {
this.groups = groups;
}
}
My RSVP
#Entity
#Table(name="RSVP")
public class RSVP {
#Id
#Column(name="RSVP_ID")
#SequenceGenerator(name="rsvp", sequenceName="RSVP_PK_SEQ")
#GeneratedValue(generator="rsvp",strategy=GenerationType.SEQUENCE)
private int rsvpId;
#OneToOne(cascade=CascadeType.REMOVE, fetch= FetchType.EAGER)
#JoinColumn(name="STATUS_ID")
private RSVPStatus status;
#ManyToOne(cascade=CascadeType.REMOVE)
#JoinColumn(name="USER_ID")
private User user;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="EVENT_ID")
private Event event;
public RSVP(int rsvpId, RSVPStatus status, User user, Event event) {
super();
this.rsvpId = rsvpId;
this.status = status;
this.user = user;
this.event = event;
}
public RSVP() {
}
#Override
public String toString() {
return "RSVP [rsvpId=" + rsvpId + ", status=" + status + ", user=" + user + ", event=" + event + "]";
}
public int getRsvpId() {
return rsvpId;
}
public void setRsvpId(int rsvpId) {
this.rsvpId = rsvpId;
}
public RSVPStatus getStatus() {
return status;
}
public void setStatus(RSVPStatus status) {
this.status = status;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Event getEvent() {
return event;
}
public void setEvent(Event event) {
this.event = event;
}
}
MY controller
public class MyController {
private static SessionFactory sf = HibernateUtils.getSessionFactory();
private DataFacade df = new DataFacade(sf);
#RequestMapping(value="home", method=RequestMethod.GET,
consumes= MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<List<Event>> getUserCal(){
DataFacade df = new DataFacade(sf);
List<Event> events= df.getAllEventsByAuthor(1);
for(Event e:events){
System.out.println(e);
}
return new ResponseEntity<List<Event>>(events,HttpStatus.OK);
}
}
Your RSVP collection is fetched lazily. (If you don't specify a fetch type, the default is lazy). You need to change it to eager if you are planning to access it after the Hibernate session is closed:
#OneToMany(cascade = CascadeType.ALL, fetch= FetchType.EAGER)
private Set<RSVP> rsvps = new HashSet<RSVP>();
I have the following query in my repository:
SELECT p FROM Project p JOIN p.users u WHERE u.login =:login
There is a Many To Many relationshio between user and project.
Everything works fine and it returns the user's projects, but I want it for each project to return the corresponding set of users. So updated it with a fetch join:
SELECT p FROM Project p JOIN FETCH p.users JOIN p.users u WHERE u.login =:login
But now i got the following exception:
nested exception is java.lang.IllegalArgumentException: Count query validation failed for method public abstract org.springframework.data.domain.Page com.example.app.repository.ProjectRepository.findAllByUserLogin(java.lang.String,org.springframework.data.domain.Pageable)! org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
Cannot find a workaround for it to execute the where clause and fetch the collection at the same time.
Project Entity:
#Entity
#Table(name = "project")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "project")
public class Project implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Size(min = 10, max = 50)
#Column(name = "name", length = 50, nullable = false)
private String name;
#Size(max = 150)
#Column(name = "description", length = 150)
private String description;
#Column(name = "project_type")
private Integer projectType;
#Column(name = "is_active")
private Boolean isActive;
#Column(name = "date_created")
private ZonedDateTime dateCreated;
#Column(name = "date_updated")
private ZonedDateTime dateUpdated;
#ManyToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "project_user",
joinColumns = #JoinColumn(name="projects_id", referencedColumnName="ID"),
inverseJoinColumns = #JoinColumn(name="users_id", referencedColumnName="ID"))
private Set<User> users = new HashSet<>();
#OneToMany(mappedBy = "project")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Milestone> milestones = new HashSet<>();
#OneToMany(mappedBy = "project")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<TaskList> taskLists = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getProjectType() {
return projectType;
}
public void setProjectType(Integer projectType) {
this.projectType = projectType;
}
public Boolean isIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
public ZonedDateTime getDateCreated() {
return dateCreated;
}
public void setDateCreated(ZonedDateTime dateCreated) {
this.dateCreated = dateCreated;
}
public ZonedDateTime getDateUpdated() {
return dateUpdated;
}
public void setDateUpdated(ZonedDateTime dateUpdated) {
this.dateUpdated = dateUpdated;
}
public Set<User> getOwners() {
return users;
}
public void setOwners(Set<User> users) {
this.users = users;
}
public Set<Milestone> getMilestones() {
return milestones;
}
public void setMilestones(Set<Milestone> milestones) {
this.milestones = milestones;
}
public Set<TaskList> getTaskLists() {
return taskLists;
}
public void setTaskLists(Set<TaskList> taskLists) {
this.taskLists = taskLists;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Project project = (Project) o;
if(project.id == null || id == null) {
return false;
}
return Objects.equals(id, project.id);
}
#Override
public int hashCode() {
return Objects.hashCode(id);
}
#Override
public String toString() {
return "Project{" +
"id=" + id +
", name='" + name + "'" +
", description='" + description + "'" +
", projectType='" + projectType + "'" +
", isActive='" + isActive + "'" +
", dateCreated='" + dateCreated + "'" +
", dateUpdated='" + dateUpdated + "'" +
'}';
}
}
User Entity:
#Entity
#Table(name = "user")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "user")
public class User extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Pattern(regexp = Constants.LOGIN_REGEX)
#Size(min = 1, max = 100)
#Column(length = 100, unique = true, nullable = false)
private String login;
#JsonIgnore
#NotNull
#Size(min = 60, max = 60)
#Column(name = "password_hash",length = 60)
private String password;
#Size(max = 50)
#Column(name = "first_name", length = 50)
private String firstName;
#Size(max = 50)
#Column(name = "last_name", length = 50)
private String lastName;
#Email
#Size(max = 100)
#Column(length = 100, unique = true)
private String email;
#NotNull
#Column(nullable = false)
private boolean activated = false;
#Size(min = 2, max = 5)
#Column(name = "lang_key", length = 5)
private String langKey;
#Size(max = 20)
#Column(name = "activation_key", length = 20)
#JsonIgnore
private String activationKey;
#Size(max = 20)
#Column(name = "reset_key", length = 20)
private String resetKey;
#Column(name = "reset_date", nullable = true)
private ZonedDateTime resetDate = null;
#Column(name = "avatar", nullable = true)
private String avatar;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login.toLowerCase(Locale.ENGLISH);
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean getActivated() {
return activated;
}
public void setActivated(boolean activated) {
this.activated = activated;
}
public String getActivationKey() {
return activationKey;
}
public void setActivationKey(String activationKey) {
this.activationKey = activationKey;
}
public String getResetKey() {
return resetKey;
}
public void setResetKey(String resetKey) {
this.resetKey = resetKey;
}
public ZonedDateTime getResetDate() {
return resetDate;
}
public void setResetDate(ZonedDateTime resetDate) {
this.resetDate = resetDate;
}
public String getLangKey() {
return langKey;
}
public void setLangKey(String langKey) {
this.langKey = langKey;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
if (!login.equals(user.login)) {
return false;
}
return true;
}
#Override
public int hashCode() {
return login.hashCode();
}
#Override
public String toString() {
return "User{" +
"login='" + login + '\'' +
", avatar='" + avatar + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", activated='" + activated + '\'' +
", langKey='" + langKey + '\'' +
", activationKey='" + activationKey + '\'' +
"}";
}
}
Try to remove second join:
SELECT p FROM Project p JOIN FECTH p.users u WHERE u.login =:login
And if you want to get Projects which contains specified user by login then you can try this:
SELECT p FROM Project p JOIN FECTH p.users u WHERE :login in elements(u.login)