Removing entities from another entity but not from database - java

I have two entities: Player and Team:
Player:
#Data
#Entity
public class Player {
#Column(nullable = false)
private String username;
#OneToOne
#JoinColumn(name = "team")
#JsonIgnore
private Team team;
}
Team:
#Entity
#Data
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToOne(fetch = FetchType.EAGER)
private User captain;
#OneToMany(fetch = FetchType.EAGER)
private List<User> players;
}
TeamRepository:
#Repository
public interface TeamRepository extends JpaRepository<Team, Long> {
}
I want to delete the whole Team from database using delete() method from JPA. Unfortunately when I do so, all Players are also deleted from my database. I only want to detach them from the Team.
Adding cascade = CascadeType.ALL/DELETE to Team and calling delete() method results in User entities deletion from database, and that's what I don't want to happen.
Adding cascade = CascadeType.DETACH to Team and calling delete() throws me a
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`32308008_localdb`.`users`, CONSTRAINT `FKhn2tnbh9fqjqeuv8ehw5ple7a` FOREIGN KEY (`team_id`) REFERENCES `team` (`id`))
exception and I have no idea why.
If someone have an idea how to delete Team entity and detach User from context but not from database I would be VERY thankful!

Related

Spring boot Jpa Entity, map same referenced column as id and entity

I have two tables user and student. Student and user has one to one relationship.
I am mapping same column with both userId and UserEntity inside StudentEntity
#Entity
#Table(name = "user")
public class User {
#Id
private UUID id;
#Column(name = "name")
private String name;
...
// getter setter ignored for brevity
}
#Entity
#Table(name = "student")
public class Student {
#Id
private UUID id;
#Column(name = "user_id")
private UUID userId;
#OneToOne
#JoinColumn(name = "user_id", referencedColumnName = "id",
insertable = false, updatable = false)
private UserEntity userEntity;
...
// getter setter ignored for brevity
}
#Repository
public interface StudentRepository extend PagingAndSortingRepository<StudentEntity, UUID> {
Optional<StudentEntity> findByUserId(UUID userId);
}
Now when I call any of below method UserEntity is not populated
StudentEntity student = studentRepository.findByUserId(userId).get()
student.getUserId() --- this is present
student.getUserEntity() -- NULL
Not sure why UserEntity is not getting populated as a part of this call.
The issue is most likely that your persistence context still contains the entity that you previously saved (which has no user set). You would first have to clear the persistence context and the load it again to see a non-null user.
Anyway, like suggested in the comments, I would advise you to just map the user. You don't need the userId field. The way you mapped it now, you should be able to use the following:
Optional<StudentEntity> findByUserEntityId(UUID userId);
Also read the official documentation for more information on the matter: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-property-expressions
You can try reverse mapping mapping like below by using mappedby in the owner of the relationship
jpa hibernate #OneToOne #JoinColumn referencedColumnName ignored

Strange behaviour of spring data jpa

I'm new to JPA and I have a case where in my opinion JoinColumn behaves different and I want to know why.
UserEntites should join authorites.
Organziations should join OrganizationSettings.
I have two different approaches and both work.
Case 1
UserEntity :
#Entity
#Table(name = "users")
#Inheritance(strategy = InheritanceType.JOINED)
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "userId")
private List<UserAuthority> authorities;
}
UserAuthoritiesEntity
#Entity(name = "authorities")
#Table(name = "authorities")
public class UserAuthority {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private String authority;
}
Here in my opinion the JoinColumn name references to UserAuthority.userId - and it works as expected.
Case 2
See my two other classes:
OrganizationEntity:
#Entity
#Table(name="organization")
public class OrganizationEntity {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
#NotNull
private String url;
#NotNull
private String name;
#OneToOne (cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name="id",updatable = false)
private OrganizationSettingsEntity settings;
}
OrganizationSettings:
#Entity
#Table(name = "organization_settings")
public class OrganizationSettingsEntity {
#Id
private Long organizationId;
}
As you can see here -> Organization is Joining OrganizationSettings with the name id - which works. But in OrganizationSettings there is no id - just organizationId. This works - but makes me wonder.
Why does the second one also work? Shouldn't it be #JoinColumn(name="organizationId") ?
Spring is nothing to do with it. JPA is a standard API.
1-N case : you will create a FK column in the authorities table with name userId (linking back to the users table). You seem to also want to REUSE that same column for this userId field in the element ... this will cause you problems sooner or later since reusing columns without marking the userId field as insertable=false, updatable=false will mean that both may try to update it. Either get rid of the userId field in the element, or convert the field to be of type UserEntity (and have it as a bidirectional relation, using mappedBy on the 1-N owner field), or mark the userId field with those attributes mentioned earlier.
1-1 case : you will create a FK column in the organization table with name id (linking across to the organization_settings table). Sadly this is the same column as the PK of that table is going to use, so again you are reusing the column for 2 distinct purposes, and hell will result. Change the column of the relation FK to something distinct - the FK is in the organization table, not the other side.

#OneToOne mappedBy insertion error

I have two entity classes User and Record related to user and record table, where the record table has a column for user_id. But the user table doesnot need to have a record_id, so that mappedBy is used. My entity class mapping is as follows:
#JsonInclude(Include.NON_NULL)
#Entity
public class Record{
#Id
#GeneratedValue
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="user_id")
private User user;
.....getters and setters
}
#JsonInclude(Include.NON_NULL)
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToOne(cascade = CascadeType.ALL, mappedBy="user")
private Record record;
....getters and setters
}
While an insert method, the functionality is like that both the tabes will be filled. The user table and record table is filled while insert method execution, except the user_id column in record table.
What may be the issue. Any help apprciated.

Hibernate throws Cannot delete or update a parent row: a foreign key constraint fails

I am working on a basic example to test cascade delete operation but I am getting exception.
I have below entities:
Employee.java
#Entity
public class Employee {
#Id
#Column(name = "EMP_ID")
private long id;
private String name;
#OneToMany(mappedBy = "employee")
#Cascade(value = { CascadeType.REMOVE, CascadeType.SAVE_UPDATE })
private List<EmpDetails> details = new ArrayList<EmpDetails>();
}
EmpDetails.java
#Entity
public class EmpDetails {
#Id
private long id;
private int info;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "EMP_ID")
private Employee employee;
}
Now I have records in databse with employee id as 10 and corresponding records in employee details table.
Now when I run below query:
session.beginTransaction();
session.delete(new Employee(10)); // here 10 is the ID of the employee
session.getTransaction().commit();
session.close();
I was thinking hibernate will delete the employee record and the corresponding employee details records as I have set the cascade type to remove. But I am getting exception as :
Caused by:
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException:
Cannot delete or update a parent row: a foreign key constraint fails
Can someone please help me how to test the cascade delete option here?
The REMOVE cascade type is for the standard JPA remove() operation. For the native Hibernate delete() operation, you need to use a Hibernate-proprietary annotation:
#Cascade(CascadeType.DELETE)
When you delete Employee on session try to add this, I had the same issue:
session.delete(session.get(Employee.class, employee_Id));
On my issue I had Movie and TimeTable relation was OneToOne:
On Movie model:
public class Movie implements Serializable
{
#Id
#Column(name = "fid")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int fid;
....
#OneToOne(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private TimeTable timetable;
}
On TimeTable model:
public class TimeTable implements Serializable
{
...
#OneToOne
#JoinColumn(name = "fid")
private Movie movie;
}

JPA CascadeType.REMOVE not working

I have two entities Business which is composed of a list of Departments
#Entity
#Table(name = "Business")
public class Business implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private Long id;
#OneToMany(mappedBy = "business",
cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private List<Department> departments;
#OneToMany(mappedBy = "business", orphanRemoval = true,
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private List<Process> processs;
#ManyToMany
private List<Competence> competences;
}
#Entity
#Table(name = "Department")
public class Department implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "father",
cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private List<Department> departments;
}
When I try to remove a business instance I get a Mysql Exception
Cannot delete or update a parent row: a foreign key constraint fails (evac_java.Department, CONSTRAINT FK_Department_Business FOREIGN KEY (Business) REFERENCES Business (Id)):HY000 - null
Which means I can't delete the business instance because it has departments associated with it, but a department cannot exists by itself so I want to delete all business's departments when it gets removed. I thought I would achieve this by adding cascade = CascadeType.REMOVE to the #OneToMany annotation in the business entity, but it does not work.
I did a search on the net and I found a lot of questions similar to this one on stackoverflow but they all suggest the same: add cascade = CascadeType.REMOVE or CascadeType.ALL
So I'm wondering if I'm missing somethig.
I'm using Glassfish 4.1 and EclipseLink
I tried with
#OneToMany(mappedBy = "business", orphanRemoval = true)
private List<Department> departments;
on the business entity but it does not work either
Here's the method I'm using to remove entities which is declared in an abstract class
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
JPA can only remove and cascade the remove over entities it knows about, and if you have not been maintaining both sides of this bidirectional relationship, issues like this will arise. If the collection of departments is empty, try an em.refresh() before the remove, forcing JPA to populate all relationships so that they can be correctly removed, though it is better to maintain both sides of the relationship as changes are made to avoid the database hit.

Categories

Resources