Delete Cascade doesn`t work, already tried every solution I found - java

Spring Rest API application. So, when I delete one User(I want to delete also the orders for that user). The user id is foreign key for the order(one to many relation).
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#OneToMany(
mappedBy = "order_products",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<OrderHasProduct> orders = new ArrayList<>();
The user class
#OneToMany(
mappedBy = "orders",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<OrderHasProduct> orders = new ArrayList<>();
public boolean deleteUser(int id){
User usr = usrRepository.findById(id);
if (usr == null) {
throw new ResourceNotFoundException(User.class.getSimpleName());
}
usrRepository.delete(id);
User deletedUser = usrRepository.findById(id);
if (deletedUser != null)
return false;
return true;
}

Can you show the OrderHasProduct class as well?
Here’s an working example:
#Entity
public class Post {
#Id
#GeneratedValue
private Long id;
private String title;
#OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
//Constructors, getters and setters
}
#Entity
public class PostComment {
#Id
#GeneratedValue
private Long id;
private String review;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "post_id")
private Post post;
//Constructors, getters and setters
}
}

Related

Hibernate One to Many relation- Child table not updating

Here I am adding a list of new orders to a specific user. While adding orders to a specific user, it returns success status, but still my database is empty. Why the data is not getting added...?
Users
#Entity
Class Users{
#Id
private int id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private List<Orders> orders;
}
Orders
#Entity
Class Orders{
#Id
private int id;
private Date orderDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
}
Repository
public ResponseEntity<String> addOrder(int userId,List<Orders> orders) throws UserNotFound{
User user =userRepository.findById(userId).orElse(null);
if(user==null) throw new UserNotFound("User Not Found");
for(Orders o:orders){
o.setOrderDate(new Date("....."));
}
user.getOrders().addAll(orders);
userRepository.save(user);
}
Try to add cascade persist to your relation specification:
#Entity
Class Users{
#Id
private int id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade={CascadeType.PERSIST})
private List<Orders> orders;
}

How to add data to Many to Many association with extra column using JPA, Hibernate

I have a User table and a Book table that I would like to connect.
So I created third table Borrow that has foreign key (book_id, user_id) and takenDate and broughtDate fields.
User.java
#Entity
#Table(name = "Users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String surname;
private String username;
private String email;
private String password;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Borrow> borrow;
....
Book.java
#Entity
#Table(name = "Books")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
private String ISBN;
private String author;
private String issuer;
private Integer dateOfIssue;
private Boolean IsRented;
#OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Borrow> borrow;
.....
Borrow.java
#Entity
#Table(name = "Borrows")
#IdClass(BorrowId.class)
public class Borrow {
private Date takenDate;
private Date broughtDate;
//lazy means it will get details of book
// only if we call GET method
#Id
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "book_id", referencedColumnName = "id")
private Book book;
#Id
#JsonIgnore
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
....
BorowId.java
public class BorrowId implements Serializable {
private int book;
private int user;
// getters/setters and most importantly equals() and hashCode()
public int getBook() {
return book;
}
public void setBook(int book) {
this.book = book;
}
public int getUser() {
return user;
}
public void setUser(int user) {
this.user = user;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BorrowId)) return false;
BorrowId borrowId = (BorrowId) o;
return getBook() == borrowId.getBook() &&
getUser() == borrowId.getUser();
}
#Override
public int hashCode() {
return Objects.hash(getBook(), getUser());
}
}
My MySql database design looks like this:
I am trying to add data to Borrow table something like this:
EDITED
#Transactional
#PostMapping("/addUser/{id}/borrow")
public ResponseEntity<Object> createItem(#PathVariable int id, #RequestBody Borrow borrow, #RequestBody Book book){
Optional<User> userOptional = userRepository.findById(id);
Optional<Book> bookOptional = bookRepository.findById(book.getId());
if(!userOptional.isPresent()){
throw new UserNotFoundException("id-" + id);
}
User user = userOptional.get();
borrow.setUser(user);
borrow.setBook(book);
borrowRepository.save(borrow);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(borrow.getId()).toUri();
return ResponseEntity.created(location).build();
}
I have't finished it because I am not sure how :/
Any tip is appreciated!
You are almost there. You just have to keep in mind two things:
1) You have to fetch the Book via repository as well (you only fetch the User currently)
2) All three operation have to be within the same transactional context:
fetching of `User`, fetching of `Book` and save `Borrow` entity.
TIP: You can put all these inside a Service and mark it as #Transactional or mark the #Post method as #Transactional. I would suggest first option, but it is up to you.
EDIT:
Optional<Book> bookOptional = bookRepository.findById(book.getId());
Also, it seems adequate to use #EmbeddedId instead of #IdClass here as ids are actual foreign entities:
#Embeddable
public class BorrowId{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "book_id", referencedColumnName = "id")
private Book book;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
}
and then in the Borrow class:
#Entity class Borrow{
#EmbeddedId BorrwId borrowId;
...
}
and in the Post method:
BorrowId borrowId = new BorrowId();
borrowId.setUser(user);
borrowId.setBook(book);
borrow.setBorrowId(borrowId);
borrowRepository.save(borrow);

Many to many org.hibernate.PersistentObjectException: detached entity passed to persist

I write my first java application to read rss stream and use spring, spring-data, hibernate.
My models.
RssFeed:
#Entity(name = "RssFeed")
#Table(name = "FEED")
#JsonIgnoreProperties({"rssChannel"})
public class RssFeed {
#Id
#GeneratedValue
#Column
private Integer id;
#Column(unique = true)
#Index(name = "title_index")
private String title;
#Column
#URL
private String link;
#Column
private String description;
#Column
private String content;
#Column
#Temporal(TemporalType.TIMESTAMP)
private Date pubDate;
#Column
#Temporal(TemporalType.TIMESTAMP)
private Date updateDate;
#ManyToOne
#JoinColumn(name = "channelId")
private RssChannel rssChannel;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "feed_category",
joinColumns = {#JoinColumn(name = "feed_id", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "category_id", nullable = false, updatable = false)})
private Set<RssCategory> rssCategories = new LinkedHashSet<RssCategory>();
}
RssChannel:
#Entity(name = "RssChannel")
#Table(name = "Channel",
uniqueConstraints = #UniqueConstraint(columnNames = {"link"}))
#JsonIgnoreProperties({"feeds"})
public class RssChannel implements Serializable{
#Id
#GeneratedValue
#Column
private Integer id;
#Column
private String title;
#Column(unique = true)
#org.hibernate.validator.constraints.URL
private String link;
#Column
#org.hibernate.validator.constraints.URL
private String image;
#Column
private String description;
#OneToMany(mappedBy = "rssChannel", cascade = CascadeType.ALL, orphanRemoval = true)
private List<RssFeed> feeds = new LinkedList<RssFeed>();
}
And RssCategory:
#Entity(name = "RssCategory")
#Table(name = "CATEGORY")
#JsonIgnoreProperties({"rssFeeds"})
public class RssCategory {
#Id
#GeneratedValue
#Column
private Integer id;
#Column(unique = true)
private String title;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "rssCategories")
public Set<RssFeed> rssFeeds = new LinkedHashSet<RssFeed>();
}
I use CrudRepository for manipulation with data. When save RssFeed without many to many it`s ok:
RssChannel channel = rssChannelService.get(url.toString());
rssFeed.setRssChannel(channel);
rssFeedService.save(rssFeed);
But when i add RssCategory:
rssCategory rssCategory = rssCategoryService.findOrCreate("test");
rssFeed.getRssCategories().add(rssCategory);
rssFeedService.save(rssFeed);
get exception: rg.hibernate.PersistentObjectException: detached entity passed to persist: RssCategory.
My RssFeedServiceImpl:
#Service
public class RssFeedServiceImpl implements RssFeedService {
#Autowired
private RssChannelDAO rssChannelDAO;
#Autowired
private RssFeedDAO rssFeedDAO;
#Override
public Page<RssFeed> findAll(Pageable pageable) {
return rssFeedDAO.findAll(pageable);
}
#Override
public Page<RssFeed> findAll(int rssChannelId, Pageable pageable) {
RssChannel rssChannel = rssChannelDAO.findOne(rssChannelId);
return rssFeedDAO.findByRssChannel(rssChannel, pageable);
}
#Override
public RssFeed get(String title) {
return rssFeedDAO.findByTitle(title);
}
#Override
public RssFeed save(RssFeed rssFeed) {
return rssFeedDAO.save(rssFeed);
}
}
And RssCategoryServiceImpl:
#Service
public class RssCategoryServiceImpl implements RssCategoryService {
#Autowired
RssCategoryDAO rssCategoryDAO;
#Override
public RssCategory findOrCreate(String title) {
RssCategory category = rssCategoryDAO.findByTitle(title);
if (category == null) {
category = new RssCategory();
category.setTitle(title);
category = rssCategoryDAO.save(category);
}
return category;
}
}
How save many to many?
You probably need to save your RssCategory first, in order to have an ID to store in feed_category table. This last save will be automatically made when you make the assignment:
rssFeed.getRssCategories().add(rssCategory);
but first you need to do:
rssFeedService.save(rssCategory);
Probably you'll need to put this operations within a transaction.

Is it possible to have the same "OneToOne"-Relationship twice in hibernate?

I didn't know how to describe my question in the title but I hope it will do.
So here is my situation.
I use hibernate to map my entities to db tables.
I got one entity like this:
#Entity
#Table(name = "EX.EXAMPLE")
public abstract class Entity
{
private CustomEntity customEntity;
public static final String CUSTOM_ENTITY = "customEntity";
#OneToOne(cascade = CascadeType.ALL, mappedBy = CustomEntity.ENTITY, fetch = FetchType.LAZY)
#Fetch(FetchMode.SELECT)
public CustomEntity getCustomEntity()
{
return this.customEntity;
}
}
And my CustomEntity
#Entity
#Table(name = "EX.EXAMPLE2")
public class CustomEntity
{
private Entity entity;
public static final String ENTITY = "entity";
#OneToOne
#JoinColumn(name = "ID_ENTITY", nullable = true)
public Entity getEntity()
{
return this.ntity;
}
}
So here is my question: Is it possible to add another CustomEntity relation to Entity? And how do I map it?
Example what I mean:
#Entity
#Table(name = "EX.EXAMPLE")
public abstract class Entity
{
private CustomEntity customEntity;
public static final String CUSTOM_ENTITY = "customEntity";
private CustomEntity customEntity2;
public static final String CUSTOM_ENTITY2 = "customEntity2";
#OneToOne(cascade = CascadeType.ALL, mappedBy = CustomEntity.ENTITY, fetch = FetchType.LAZY)
#Fetch(FetchMode.SELECT)
public CustomEntity getCustomEntity()
{
return this.customEntity;
}
#OneToOne(cascade = CascadeType.ALL, mappedBy = CustomEntity.ENTITY, fetch = FetchType.LAZY)
#Fetch(FetchMode.SELECT)
public CustomEntity getCustomEntity2()
{
return this.customEntity2;
}
}
I only managed it by changing customEntity to a list in Entity.
Greetings
Yes, that is perfectly normal situation. You just need two fields with different mappedBy`, one for each relation
#OneToOne(cascade = CascadeType.ALL, mappedBy = CustomEntity.ENTITY1, fetch = FetchType.LAZY)
#Fetch(FetchMode.SELECT)
public CustomEntity getCustomEntity()
{
return this.customEntity;
}
#OneToOne(cascade = CascadeType.ALL, mappedBy = CustomEntity.ENTITY2, fetch = FetchType.LAZY)
#Fetch(FetchMode.SELECT)
#JoinColumn(name = "entity_2_id")
public CustomEntity getCustomEntity2()
{
return this.customEntity2;
}
And two fields in CustomEntity, one for each mapping
#OneToOne
#JoinColumn(name = "ID_ENTITY_1", nullable = true)
public Entity getEntity1()
{
return this.entity1;
}
#OneToOne
#JoinColumn(name = "ID_ENTITY_2", nullable = true)
public Entity getEntity2()
{
return this.entity2;
}

Two references in the same entity to another entity

I have the entity User, this entity is used twice in another entity Product. I use hibernate and foreign keys between tables are created. There are also two foreign keys - for create_by and modified_by.
class User
class User {
private Set<Product> products = new HashSet<Product>(0);
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
public Set<ProductgetProducts{
return this.products
}
public void setProducts(Set<Product> products) {
this.products = products
}
}
class Product
class Product {
private User createdBy;
private User modifiedBy;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name = "modified_by", nullable = false)
public User getModifiedBy() {
return modifiedBy;
}
public void setModifiedBy(User createdBy) {
this.modifiedBy= modifiedBy;
}
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name = "created_by", nullable = false)
public User getCreatedBy() {
return createdBy;
}
public void setCreatedBy(User createdBy) {
this.createdBy = createdBy;
}
}
It throws me this exception and I don't know how to fix it.
Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: Product.user in User.products
mappedBy = "user"means: I'm the inverse side of a bidirectional association, whose owner side is the field user in the target entity (i.e. Product). There is no user field in Product. So it doesn't make sense.
If you want the createdBy ad modifiedBy associations to be bidirectional, you need two fields in User:
#OneToMany(mappedBy = "createdBy")
private Set<Product> createdProducts;
#OneToMany(mappedBy = "modifiedBy")
private Set<Product> modifiedProducts;

Categories