so i am trying to set two related object in each other's fields. But when i debug the code i get that after i set the first object as a field in the other i am getting the following error: com.sun.jdi.InvocationException: Exception occurred in target VM occurred invoking method.
Here is the source code, i hope someone can help. Thank you :D
#Service #Transactional
public class MainService {
#Autowired CustomTableRepository tRepo;
#Autowired UserRepository uRepo;
#Autowired ReservationRepository rRepo;
#SneakyThrows
public void reserveTable(Reservation reservation) {
CustomTable table = tRepo.findById(reservation.getTable().getId()).get();
User user = uRepo.findByUsername(reservation.getUser().getUsername());
Reservation myReservation = new Reservation(null, reservation.getAccepted(), user, table, reservation.getTime());
rRepo.saveAndFlush(myReservation);
if(!(reservationRequirements(rRepo.findByUser(user))))
throw new Exception("something went wrong with the reservation, regarding the requierements");
else {
user.setBalance(user.getBalance() - CONSTANTS.fee );
user.setReservation(myReservation);
myReservation.setAccepted(true);
myReservation.setTable(table);
myReservation.setUser(user);
table.setReservation(myReservation);
table.setAvailable(false);
uRepo.saveAndFlush(user);
tRepo.saveAndFlush(table);
rRepo.save(myReservation);
}
}
/*
* PRIVATE HELPING METHODS
*/
private Boolean reservationRequirements(Reservation reservation) {
User user = uRepo.findByUsername(reservation.getUser().getUsername());
//check if the user has enough money
if(user.getBalance() < CONSTANTS.fee)
return false;
//check if they accepted the money fee.
if(reservation.getAccepted() == false)
return false;
//if the table is occupied
if(reservation.getTable().getAvailable() == null) {
}else {
if(reservation.getTable().getAvailable() == false)
return false;
}
LocalTime time = CONSTANTS.parseLocalTime(reservation.getTime());
if(!(time.isAfter(LocalTime.parse("07:30")) && time.isBefore(LocalTime.parse("22:00"))))
return false;
return true;
}
}
This is how they are all related one to other:
Entity classes:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CustomTable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Boolean available;
private Boolean busy;
private Boolean arrived;
#OneToOne(mappedBy = "table", cascade = CascadeType.ALL, orphanRemoval = true)
private Reservation reservation;
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Reservation {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private Boolean accepted;
#OneToOne
#JoinColumn(name = "user_id")
private User user;
#OneToOne
#JoinColumn(name = "table_id")
private CustomTable table;
private String time;
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String type;
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String username;
private String password;
private Long number;
private Long balance;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private Reservation reservation;
#ManyToMany(fetch = FetchType.EAGER)
private Collection<Role> roles;
}
Thank you a lot for reading.
Related
I have already built projects similar to this one, I even based this one in a different project I have. Thing is, I don't see why it keeps failing when I try to save an object to the Database. These are my Classes:
Car
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity(name = "cars")
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
#NotBlank
private String brand;
#Column
#NotBlank
private String model;
#Column
#NotBlank
private String color;
#Column
#NotBlank
private int kilometers;
#Column(name = "fabrication_date")
private LocalDate fabricationDate;
#Column
#PositiveOrZero
private float price;
#Override
public String toString() {
return "------------------------------------------------------------"+ "\n"
+brand + " - " + model;
}
#OneToMany(mappedBy = "car")
#JsonBackReference(value = "car-purchases")
private List<Purchase> purchases;
}
Purchase
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "purchases",
uniqueConstraints = { #UniqueConstraint(columnNames =
{ "user_id", "car_id" }) })
public class Purchase {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "creation_date")
private LocalDate creationDate;
#Column
private float price;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToOne
#JoinColumn(name = "car_id")
private Car car;
}
This is the Add to Database function:
#Override
public CarOutDTO addCar(CarInDTO carInDTO) {
Car car = new Car();
modelMapper.map(carInDTO, car);
car.setFabricationDate(LocalDate.now());
car.setKilometers(0);
Car newCar = carRepository.save(car); <--- It fails here
CarOutDTO carOutDTO = new CarOutDTO();
modelMapper.map(car, carOutDTO);
return carOutDTO;
}
And, this is the info that comes when I try sending a POST:
I can't find the error here, I assume it has something to do with this part, maybe the #JsonBackReference part?
#OneToMany(mappedBy = "car")
#JsonBackReference(value = "car-purchases")
private List<Purchase> purchases;
I have a OneToOne relation between tables User and Profile defined like so:
#Entity
#Builder
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name="users", uniqueConstraints = {
#UniqueConstraint(columnNames = "username"),
#UniqueConstraint(columnNames = "email")
}
)
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idUser;
private String username;
private String email;
private String password;
#OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)
#JoinColumn(name="id_profile", referencedColumnName="idProfile")
private Profile profile;
#ManyToMany(fetch = FetchType.EAGER)
private Set<Role> roles = new LinkedHashSet<Role>();
}
#Entity
#Data
#Builder
#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;
private String discordId;
private String description;
#ElementCollection(fetch=FetchType.EAGER)
private Set<String> spokenLanguages = new LinkedHashSet<String>();
#OneToMany(fetch=FetchType.EAGER)
private Set<ProfileGame> profileGames = new LinkedHashSet<>();
#OneToOne(mappedBy="profile")
private User user;
#ManyToOne
private TimeSlot timeSlot;
}
Then I run a test to make some fixtures in my database:
Profile profile = this.profileRepository.save(Profile.builder()
.birthday(new Date())
.discordId("discord-" + i)
.description("Description de user-" + i)
.spokenLanguages(spokenLanguages)
.timeSlot(timeSlot)
.build());
user.setProfile(profile);
System.err.println(user);
Everything works fine here, System.err.println(user) returns correct values.
The issue comes from the database, which doesn't "apply" the id_profile in my User table:
What did I miss?
Try to do something like this:
Profile profile = Profile.builder()
.birthday(new Date())
.discordId("discord-" + i)
.description("Description de user-" + i)
.spokenLanguages(spokenLanguages)
.timeSlot(timeSlot)
.user(user)
.build();
user.setProfile(profile);
profile = this.profileRepository.save(profile);
You use a bidirectional #OneToOne association, so you should make sure both sides are in-sync at all times.
Also, as you need to propagate persistent state to the user, you should add cascade = CascadeType.ALL to the Profile.user like below:
#Entity
public class Profile implements Serializable {
// ...
#OneToOne(mappedBy="profile", cascade=CascadeType.ALL)
private User user;
}
Class User:
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL,
fetch = FetchType.LAZY, optional = false)
private Profile profile;
Class Profile:
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name="id_user")
private User user;
I have 2 entities, connected by many to many. The template should list:
Owner1
shelter1
shelter 2
Owner1
shelter 1
How can I connect the Owner and the Shelter in the controller so that I can pinch into the template
Owner 1- his shelters
Owner 2 - His Shelters
The whole problem is in the controller, what exactly should I pass to the template engine? This is the whole problem, thanks in advance for the answers and time taken
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#DynamicUpdate
#Entity
#Table(name = "owner")
public class Owner {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idOwner;
private String name;
private String address;
private String description;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "owner_shelter",
inverseJoinColumns = { #JoinColumn(name = "shelter_id") })
private List<Shelter> shelters = new ArrayList<>();
public void addShelter(Shelter shelter) {
shelters.add(shelter);
shelter.getOwners().add(this);
}
public void removeShelter(Shelter shelter) {
shelters.remove(shelter);
shelter.getOwners().remove(this);
}
}
#Data
#DynamicUpdate
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Entity
#Table(name = "shelter")
public class Shelter {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String address;
private String description;
#ManyToMany(mappedBy = "shelters")
private List<Owner> owners;
public void addOwner(Owner owner) {
owners.add(owner);
owner.getShelters().add(this);
}
public void removeOwner(Owner owner) {
owners.remove(owner);
owner.getShelters().remove(this);
}
}
now i can print only list of shelter or owner
#Autowired
ShelterRepository shelterRepository;
#Autowired
OwnerRepository ownerRepository;
#GetMapping("/shelters")
public String getPage(Authentication authentication, Model model) {
if (authentication != null) {
model.addAttribute("authentication", authentication);
}
List<Shelter> shelters = shelterRepository.findAll();
List<Owner> owners = ownerRepository.findAll();
model.addAttribute("shelters", shelters);
model.addAttribute("owners", owners);
return "shelterList";
}
I have 2 entities, related with #OneToMany.
#Entity
#Table(name = "appeal_templates")
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class AppealTemplate extends AbstractEntity {
private List<Question> questions = new ArrayList<>();
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "template")
public List<Question> getQuestions() {
return questions;
}
}
And second one:
#Setter
#Entity
#Table(name = "appeal_template_questions")
public class Question extends AbstractEntity {
private AppealTemplate template;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "template_id")
public AppealTemplate getTemplate() {
return template;
}
}
AbstractEntity:
#MappedSuperclass
#Setter
#EqualsAndHashCode
#ToString
public abstract class AbstractEntity implements Serializable {
private static final int START_SEQ = 1000;
private Long id;
private LocalDateTime created;
private LocalDateTime updated;
#Id
#SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1, initialValue = START_SEQ)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq")
public Long getId() {
return id;
}
#Column(name = "created", updatable = false)
public LocalDateTime getCreated() {
return created;
}
#Column(name = "updated", insertable = false)
public LocalDateTime getUpdated() {
return updated;
}
#PrePersist
public void beforeCreate() {
if (Objects.isNull(created)) {
created = LocalDateTime.now();
}
}
#PreUpdate
public void beforeUpdate() {
if (Objects.isNull(updated)) {
updated = LocalDateTime.now();
}
}
}
I send dto to save like this:
AppealTemplate(id=null, questions=[Question(id=null, initial=false, rank=null, text=Quo vadis?)])
ID not filled while they not sved, both entities saving by AppealTemplate repository, but for Question field template_id not filled.
How to do that template_id filled automatically with first save?
I'm trying to make a many to many relationship using EBean in Play2 and I have an issue where EBean trows an error saying my class is not registered.
Heres my mapping classes:
#Entity
public class Booking extends Model {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
//... other fields
}
#Entity
public class Store extends Model {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
//... other fields
}
#Embeddable
public class ComissionId {
#ManyToOne(targetEntity = Booking.class, optional = false)
#PrimaryKeyJoinColumn(name = "booking_id", referencedColumnName = "id")
private Booking booking;
#ManyToOne(targetEntity = Store.class, optional = false)
#PrimaryKeyJoinColumn(name = "store_id", referencedColumnName = "id")
private Store store;
}
#Entity
#AssociationOverrides({
#AssociationOverride(name = "id.booking", joinColumns = #JoinColumn(name = "booking_id")),
#AssociationOverride(name = "id.store", joinColumns = #JoinColumn(name = "store_id"))
})
public class StoreComission extends Model {
#EmbeddedId
private ComissionId id;
#Column(nullable = false)
private double value;
#Column(nullable = false)
private Date date;
}
The error:
java.lang.RuntimeException:
Error reading annotations for models.ids.ComissionId
Caused by: java.lang.RuntimeException:
Error with association to [class models.Booking] from [models.ids.ComissionId.booking].
Is class models.Booking registered?
In my application.conf I've put ebean.default="models.*" so all this classes should be registered right? (I've tried to move the ComissionId from the package models.ids to models, but the same error ocurred)
You have this error because of #ManyToOne annotations inside your ComissionId class. To make this code work you have to move these relations to StoreComission class. In ComissionId class you should leave only identifiers. In StoreComission class #ManyToOne relation are mapped to the same columns as fields from composite key. But they have attributes 'insertable' and 'updateable' set to false to prevent column duplication.
Here is corrected working code for above scenario:
StoreComission class:
#Entity
public class StoreComission extends Model {
public StoreComission() {
id = new ComissionId();
}
#EmbeddedId
private ComissionId id;
#Column(nullable = false)
public double value;
#Column(nullable = false)
public Date date;
#ManyToOne
#JoinColumn(name = "booking_id", insertable = false, updatable = false)
private Booking booking;
#ManyToOne
#JoinColumn(name = "store_id", insertable = false, updatable = false)
private Store store;
public void setBooking(Booking aBooking) {
booking = aBooking;
id.booking_id = aBooking.id;
}
public Booking getBooking() {
return booking;
}
public void setStore(Store aStore) {
store = aStore;
id.store_id = aStore.id;
}
public Store getStore() {
return store;
}
}
ComissionId class:
#Embeddable
public class ComissionId {
public int booking_id;
public int store_id;
#Override
public int hashCode() {
return booking_id + store_id;
}
#Override
public boolean equals(final Object obj) {
return super.equals(obj);
}
}