I have a table which has a self reference join table to itself.
#Entity
public class Employee {
#OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, orphanRemoval = true)
private List<EmployeeDependency> employeeDependencies;
}
#Entity
public class EmployeeDependency {
#ManyToOne
#JoinColumn
private Employee employee;
#ManyToOne
#JoinColumn
private Employee employeeDependency;
}
As we can see the relation is managed by mappedBy = "employee".
DB looks like this for the dependency table
EmployeeDependency
----------------------------------------
id employee_id employee_dependency_id
----------------------------------------
1 2 3
2 2 4
3 3 10
Now when I try deleting employee= 2 , it is deleting the references in EmployeeDependency table and also deleting the record from Employee table as dependency is managed by employee in the mapping mappedBy = "employee". This is expected and working as it is written.
But now when I try to delete employee = 10 which is in other side of relation, I was getting foreign key reference error.
I was able to delete it if I put a dummy reference in Employee entity like this
#Entity
public class Employee {
#OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, orphanRemoval = true)
private List<EmployeeDependency> employeeDependencies;
#OneToMany(mappedBy = "employeeDependency", cascade = CascadeType.ALL, orphanRemoval = true)
private List<EmployeeDependency> dummyEmployeeDependencies;
}
But this doesn't seems to be right! how can I put a bidirectional cascade so I can delete ids from either side of relation
Related
in spring boot i want to achieve that if i can access employee table from employee_personal_detail table and also i can access
employee_persona_detail table from employee vice-versa while adding
data Why Foreign key not inserted in hibernate
so not able to access employee from access employee_persona_detail
employee table
#OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL,mappedBy = "employee")
public EmployeePersonalDetail employeePersonalDetail;
#Table(name="employee_personal_details")
#ToString
public class EmployeePersonalDetail {
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employee_id")
private Employee employee;
}
I've got the following code:
#OneToOne(cascade = ALL)
private SquadMember commander;
#OneToOne(cascade = ALL)
private SquadMember lieutenant;
#OneToMany(orphanRemoval = true, cascade = REMOVE, mappedBy = "squad")
private Set<SquadMember> memberList = new LinkedHashSet<>();
When I add a commander or lieutenant, they end up in the SquadMember table and when I retrieve the memberList from the database the commander and lieutenant are included in the memberList(basically duplicated as they're in the Squad as commander/lieutenant but also as member).
How can I fix this so that the commander / lieutenant never appear in the memberList when retrieved from the database?
Posts I've already looked at but did not find my answer:
JPA OneToOne and OneToMany on the same entity
I suppose the piece of code you have put is from the entity "Squad".
In the SquadMember entity you must have three Squad type parameters for the bidirectional mapping to be correct, since if you are going to register a lieutenant and fill in his squad when you only have one parameter, JPA and Hibernate will associate it as being part of the ONE-TO-MANY relationship.
Verify that in the SquadMember entity you have the following:
//Relation members with squad
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SQUAD_ID")
private Squad squad;
//Relation bidirectional for lieutenant
#OneToOne(fetch = FetchType.LAZY, mappedBy = "lieutenant")
private Squad squadLt;
//Relation bidirectional for commander
#OneToOne(fetch = FetchType.LAZY, mappedBy = "commander")
private Squad squadCm;
For example if you need to update commander, use squadCM, etc..
I have a relation between Accommodation and Booking classes, and also I set a foreign key in booking table.
ALTER TABLE `project`.`booking`
ADD INDEX `fk_accId_fk_idx` (`accommodation` ASC);
ALTER TABLE `project`.`booking`
ADD CONSTRAINT `fk_accId_fk`
FOREIGN KEY (`accommodation`)
REFERENCES `project`.`accommodation` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
Accommodation class:
#Entity
....
public class Accommodation implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private BigInteger id;
#OneToMany(mappedBy = "accommodation", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
#JsonManagedReference
private List < Booking > bookings;
......getters setters
}
Booking class:
#Entity
public class Booking implements Serializable {
......
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "bookings", nullable = true)
#JsonBackReference
private Accommodation accommodation;
....getters setters
}
When I execute a query for listing accommodations, I get unknown column in field list error.
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'bookings7_.bookings' in 'field list'
Even I set the relation and define the foreign key in table, what is the reason that I get this error?
Try to define your join-table mapping manually in JPA. Drop your schema and let JPA create your tables:
Accommodation class
#OneToMany(mappedBy = "accommodation", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
#JsonManagedReference
private List < Booking > bookings;
Booking class
#ManyToOne(fetch = FetchType.EAGER)
#JoinTable(name = "accommodation_booking_join_table",
joinColumns = {#JoinColumn(name="booking_id")},
inverseJoinColumns = #JoinColumn(name = "accommodation_id"))
#JsonBackReference
private Accommodation accommodation;
Try changing your column names to lower case in your db and entity class.
I had a situation like that, and I solved it by changing the field's position on the query. Looks like it's a MySQL bug, like (or the same as) the one mentioned on this post:
https://bugs.mysql.com/bug.php?id=1689
The description of this MySQL bug mentioned a similar workaround solution: "I found that by swapping that field's position in the table with another field that it worked OK."
I have a RECIPE table that has OneToMany relationship with the INGREDIENT table because a single recipe can have many ingredients. The issue is that if a user deletes an ingredient (which sets all fields (ingredient_id and ingredient) to NULL by frontend), then the row containing relationship of both the tables RECIPE_INGREDIENT is deleted but the row in the Ingredient table still exists. Can't we tell Hibernate to delete that rows also?
Oracle table
create table recipe(id number primary key,
name varchar2(25) unique);
create table ingredient(ingredient_id number(4) primary key,
ingredient varchar2(40));
create table recipe_ingredient(recipe_id number(4),
ingredient_id number(4),
constraint recipe_fk foreign key(recipe_id)
references recipe(recipe_id),
constraint ingredient_fk foreign
key(ingredient_id) references
ingredient(ingredient_id));
Ingredient and Recipe POJO
#Entity
#Table(name = "ingredient", uniqueConstraints={
#UniqueConstraint(columnNames="INGREDIENT_ID")
})
public class Ingredient implements Serializable {
#Id
#Column(name = "INGREDIENT_ID", unique=true, nullable=false)
#SequenceGenerator(name="seq_ingredient", sequenceName="seq_ingredient")
#GeneratedValue(strategy=GenerationType.AUTO, generator="seq_ingredient")
private Integer ingredientId;
#Column(name = "INGREDIENT")
private String ingredient;
/*#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="RECIPE_ID")
private Recipe recipe;*/
//getter and setters
#Entity
#Table(name = "recipe")
public class Recipe implements Serializable {
#Id
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#JoinTable(name = "recipe_ingredient", joinColumns = { #JoinColumn(name = "recipe_id") }, inverseJoinColumns = { #JoinColumn(name = "ingredient_id") })
private List<Ingredient> ingredients;
//getters and setter
}
DAO Code
public class RecipeDaoImpl implements RecipeDao {
public void addRecipe(Recipe recipe) {
getSession().saveOrUpdate(recipe);
}
}
Log that shows that the row in INGREDIENT table still exists whereas Hibernate is just deleting row from 'RECIPE_INGREDIENT' table.
Please see following that ingredient_id with null is deleted. In both cases, it is updating ingredient.recipe_id as NULL.
Received following from frontend:
RecipeController - Recipe[recipeId=126,name=Sandwich,ingredients=[Ingredient[ingredientId=270,ingredient=Salt],[ingredientId=<null>,quantity=<null>]]]
Hibernate: update RECIPE set NAME=? where RECIPE_ID=?
Hibernate: update ingredient set INGREDIENT=? where INGREDIENT_ID=?
Hibernate: delete from recipe_ingredient where recipe_id=?
Hibernate: insert into recipe_ingredient (recipe_id, ingredient_id) values (?, ?)
So the database table has,
INDREDIENT
INGREDIENT_ID INGREDIENT
271 Salt
272 Sugar
RECIPE_INDGREDIENT
RECIPE_ID INDREDIENT_ID
126 271
I solved this issue by adding insertable = false, updatable = false as attributes to #JoinColumn
Like this:
#JoinColumn(name="RECIPE_ID", insertable = false, updatable = false)
Orphan Removal in Relationships
When a target entity in one-to-one or one-to-many relationship is removed from the relationship, it is often desirable to cascade the remove operation to the target entity. Such target entities are considered “orphans,” and the orphanRemoval attribute can be used to specify that orphaned entities should be removed.
For example, if an RECIPE has many INGREDIENT and one of them is removed from the list, the removed INGREDIENT is considered an orphan. If orphanRemoval is set to true, the line item entity will be deleted when the INGREDIENT is removed from the list.
The orphanRemoval attribute in #OneToMany and #oneToOne takes a Boolean value and is by default false.
The following example will cascade the remove operation to the orphaned INGREDIENT entity when it is removed from the relationship:
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, orphanRemoval="true")
#JoinColumn(name="RECIPE_ID")
private List<Ingredient> ingredients;
To Add more
orphanRemoval and DELETE CASCADE.
orphanRemoval is an entirely ORM-specific thing. It marks "child" entity to be removed when it's no longer referenced from the "parent" entity, e.g. when you remove the child entity from the corresponding collection of the parent entity.
ON DELETE CASCADE is a database-specific thing, it deletes the "child" row in the database when the "parent" row is deleted.
I have a many-to-many relationship with three tables and entities adn the join table contains additional column. On both sides of the relationship I have set cascadeType.All
When I add new objects to owner side the merge method works fine but when I remove a child object from the owner and merge it, the corresponding rows in the join table will not be removed and I will have duplicate rows in there.
owner entity
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "definitionType")
private List<DefinitionProperty> definitionProperties = new ArrayList<DefinitionProperty>();
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "property")
private List<DefinitionProperty> definitionProperties= new ArrayList<DefinitionProperty>();
mapping entity
#Id
#JoinColumn(name = "dtid", referencedColumnName = "id")
#ManyToOne(optional = false)
private DefinitionType definitionType;
#Id
#JoinColumn(name = "prid", referencedColumnName = "id")
#ManyToOne(optional = false)
private Property property;
I am not calling remove method of my entity manager at all and I am expecting the cascading to remove the unwanted rows automatically. Is that possible? what should I do to in order to remove those rows?
I can add my code here if it help
It just needed orphanRemoval=true on the owner side.