Hibernate OnetoMany and ManyToOne throw exception - java

I'm trying to make simple one to many relationship but hibernate is throwing error, no idea what to do.
Class Product:
public class Products {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne()
#JoinColumn(name = "user_id", foreignKey = #ForeignKey(name = "fk_user"))
private Users users;
}
and Class Users:
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
#OneToMany()
#JoinColumn(name = "product_id", foreignKey = #ForeignKey(name = "fk_product_id"))
private List<Products> productsList = new ArrayList<>();
}
I got error: Error executing DDL "alter table products drop constraint fk_user" via JDBC Statement

Here is a working example of such relationship :
Drawer class :
#OneToMany (mappedBy="drawer", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, orphanRemoval = true)
private Set<Pocket> pockets;
Pocket class :
#ManyToOne (fetch=FetchType.EAGER)
#JoinColumn(name = "id_drawer", nullable = false)
private Drawer drawer;

Since the foreign key is on the child side (Products class), you can drop it on the parent side and reference to child as being the owning side:
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
#OneToMany(mappedBy="users")
private List<Products> productsList = new ArrayList<>();
}

Related

JPA/Hibernate ManyToOne Association always null

I have two entities BookingLegEntity and BookingEntity which reference each other. But anytime I try to retrieve them from the database (e.g. via findByUuid), BookingLegEntity.belongsTo remains null.
Here are my entities:
#Entity
#Table(name = "BOOKING_LEG")
#SQLDelete(sql = "UPDATE BOOKING_LEG SET deleted = true WHERE id=?")
#Where(clause = "deleted=false")
public class BookingLegEntity {
#Id
#Column(name = "ID", unique = true, updatable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "UUID", nullable = false)
private UUID uuid;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "BELONGS_TO")
private BookingEntity belongsTo;
// ..
#ManyToOne
#JoinColumn(name = "DISTRIBUTOR")
private DistributorEntity distributor;
#Column(name = "TRANSPORT_TYPE")
#Convert(converter = TripTypeEnumConverter.class)
private TripTypeEnum transportType;
// ...
}
#Entity
#Table(name="BOOKINGS")
#SQLDelete(sql = "UPDATE BOOKINGS SET deleted = true WHERE id=?")
#Where(clause = "deleted=false")
public class BookingEntity {
#Id
#Column(name="ID", unique=true, updatable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name="BOOKING_ID")
#Convert(converter = BookingIdConverter.class)
private BookingId bookingId;
#ManyToOne
#JoinColumn(name ="BOOKED_BY")
private UserEntity bookedBy;
// ..
#OneToMany(mappedBy = "belongsTo", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<BookingLegEntity> bookingLegs = new HashSet<>();
// ...
}
Here is my repository:
#Repository
public interface BookingLegRepository extends JpaRepository<BookingLegEntity, Long> {
Optional<BookingLegEntity> findByUuid(UUID id);
// ...
}
The values in the database itself look correct:
What is really strange is that this has worked before (belongsTo was not null) but suddenly stopped working. Does anyone has any idea as to what we might do wrong here?
Do not use cascade = CASCADEType.ALL on your ManyToOne annotation, because removing one BookingLeg will cause a removal of all in corresponding Booking
The solution should be to use
cascade = CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}) in its stead.
I would Truncate Cascade or Delete from Bookings where original_itinerary is null before i move on to using the new entities.
Sincerely hope it helps. (No hate if it doesn't pls)
Edit : i didnt see that comment by #dey, its my own. :P saw his comment after posting my ans

“Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements” SpringBoot

i have three entites named depense ,benifice and categories , when i want to get the benefice_C and the Depenese_C in the category entity .this error displayed to me
“Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements” SpringBoot
Depens Entities
> #Entity
#Getter
#Setter
#Table(name="depense")
public class Depense {
#Id #GeneratedValue
#Column(name = "id_etab")
private Long idEtab;
#ManyToOne
#JoinColumn(name = "personnel_id")
private Personnel personnel;
#ManyToOne
#JoinColumn(name = "CATD")
private Categories categoriesD;
Benfice Entities
> public class Benifice {
#Column(name = "id_etab")
private Long idEtab;
#ManyToOne
#JoinColumn(name = "inscrit_id")
private Inscrit inscrit;
#ManyToOne
#JoinColumn(name = "be_C")
private Categories benificeC;
Categorie entite
> public class Categories implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idCat;
#OneToMany(mappedBy = "categoriesD", fetch = FetchType.LAZY)
private Depense depense;
#OneToMany(mappedBy = "benificeC", fetch = FetchType.LAZY)
private Benifice benifice;
Your #OneToMany mapping is not correct.
You would need a List/Set/Collection of Objects if you map OneToMany.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idCat;
#OneToMany(mappedBy = "categoriesD", fetch = FetchType.LAZY)
private List<Depense> depense;
#OneToMany(mappedBy = "benificeC", fetch = FetchType.LAZY)
private List<Benifice> benifice;

Hibernate MappedBy for Multiple columns

I am using Postgresql for my database and it contains a table called user and a table called friendship, which has 2 foreign keys userA_id and userB_id. I know how to use mappedBy to check for friendships based on userA_id but I am not sure how to check for userB_id. Is there a way to tell hibernate to check a user ID from user table with both of columns on friendship table?
EDIT: Here is the code I currently have.
#Entity
#Table(name = "users")
public class UserDB implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "userid", nullable=false)
public int userID; //not null
#OneToMany (targetEntity = FriendshipDB.class, mappedBy = "userA_ID", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
//#OneToMany (targetEntity = FriendshipDB.class, mappedBy = "userB_ID", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
public List<FriendshipDB> friends = new ArrayList<>();
}
#Entity
#Table(name = "friendships")
public class FriendshipDB implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "friendshipid", nullable = false)
private int friendshipID; //not null
#ManyToOne
#JoinColumn(name="usera_id")
private UserDB userA_ID; //not null
#ManyToOne
#JoinColumn(name = "userB_id")
private UserDB userB_ID;
}
I think this is very specific mapping but the only solution I know is to go with 2 association like this:
#OneToMany(mappedBy = "user1")
private Collection<User> usersByFirst;
#OneToMany(mappedBy = "user2")
private Collection<User> usersBySecond;

spring-data-rest, manytomany relation with join table

Is it possible to expose a manytomany relationship that uses a join entity (that contains extra data columns), below is my entities;
I'm trying to get 'purchases' to show in REST, I've put in 'products' as an example of a working REST mapping;
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = Purchase.class, orphanRemoval = true)
#JoinColumn(name = "user_id", updatable = false)
private List<Purchase> purchases = new ArrayList<>();
#ManyToMany
#JoinColumn(name = "user_id", updatable = false)
private List<Product> products = new ArrayList<>();
}
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
}
#Entity
public class Purchase implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
#ManyToOne(targetEntity = Prodect.class)
#JoinColumn(name = "product_id", referencedColumnName = "id")
private Product product;
#Column(name = "purchase_date")
private Date purchaseDate;
}
So if i send the REST call;
[GET http://localhost:8080/webapp/users/1]
It returns links for [http://localhost:8080/webapp/users/1/products] but not for [http://localhost:8080/webapp/users/1/purchases]
worked out what the issue was; I need to create a JpaRepository for the Purchase entity. Soon as I added that, the REST links for purchases are available.

Two entities with #ManyToOne should join the same table

I have the following entities
Student
#Entity
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//getter and setter for id
}
Teacher
#Entity
public class Teacher implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//getter and setter for id
}
Task
#Entity
public class Task implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(optional = false)
#JoinTable(name = "student_task", inverseJoinColumns = { #JoinColumn(name = "student_id") })
private Student author;
#ManyToOne(optional = false)
#JoinTable(name = "student_task", inverseJoinColumns = { #JoinColumn(name = "teacher_id") })
private Teacher curator;
//getters and setters
}
Consider that author and curator are already stored in DB and both are in the attached state. I'm trying to persist my Task:
Task task = new Task();
task.setAuthor(author);
task.setCurator(curator);
entityManager.persist(task);
Hibernate executes the following SQL:
insert
into
student_task
(teacher_id, id)
values
(?, ?)
which, of course, leads to null value in column "student_id" violates not-null constraint
Can anyone explain this issue and possible ways to resolve it?
UPDATE
See my own solution below.
I've resolved my issue with the help of #SecondaryTable and switched from #JoinTable to #JoinColumn:
Task
#Entity
#SecondaryTable(name="student_task")
public class Task implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(optional = false)
#JoinColumn(table = "student_task", name = "student_id")
private Student author;
#ManyToOne(optional = false)
#JoinColumn(table = "student_task", name = "teacher_id")
private Teacher curator;
//getters and setters
}
Now, generated SQL looks like:
insert
into
student_task
(student_id, teacher_id, id)
values
(?, ?, ?)
and everything works just fine :)
I think you are missing the JoinColumns tag...
joinColumns = { #JoinColumn(name = "student_id", referencedColumnName = "id") }
joinColumns = { #JoinColumn(name = "teacher_id", referencedColumnName = "id") }
in author and curator respectively
Also remember, that the inversjoincolumn is the column in the owned table.. so it must be something like:
inverseJoinColumns = {#JoinColumn(name="id")})

Categories