There are two main #Entity classes reflecting these tables:
TableA {id,name}
TableB {id,name}
And one reference table
TableC {tableA.id,tableB.id}
Question is: how to map a TableA's entity's field with #OneToMany realation to TableB objects list:
#OneToMany
??????????
private List<TableBEntity> tableBItems;
If what you really have is a OneToMany (which means that a give tableB.id appears at most once in TableC), then the mapping is the following:
#OneToMany
#JoinTable(name = "TableC",
joinColumns = #JoinColumn(name = "TABLE_A_ID"),
inverseJoinColumns = #JoinColumn(name = "TABLE_B_ID"))
private List<TableBEntity> tableBItems;
Else, what you have is in fact a ManyToMany, and the mapping is the same, except that #OneToMany must be replaced by #ManyToMany.
Related
I've read some related questions but they are not exactly the same problem as mine.
I'm using JPA + Hibernate + Spring and I want to do something that I'm not sure if it is possible just with config.
I have my domain classes with a more or less complicated relation. There are many elements that are related with one element (like if it was a tree many elements are sons of one element).
Something like:
#Entity
class Foo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "PARENT_ID")
private Foo parentNode;
...
}
Which will get a table like:
Foo id parent_id
1
2 1
3 1
When I delete row with id = 1 I want to delete rows with id = 2 and id = 3 (it may be recursive, elements with parent_id = 2 and parent_id = 3 would be deleted as well).
For some restrictions I only can have the relation in son's side with the parent_id reference.
My question is: is it possible to do this with JPA or Hibernate configuration or do I need to do some recursive function to delete all children and all parents?
I've tried with:
#OneToMany(name = "PARENT_ID", cascade = CascadeType.REMOVE)
And I've read that maybe using Hibernate annotations.
If anyone can give me some clue I'm lost at this point.
Edit 1
Would it be possible to do like:
#Entity
class Foo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name="PARENT_ID")
private Foo parentNode;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "parentNode", cascade = CascadeType.REMOVE, orphanRemoval = true)
private Set<Foo> childs = new LinkedHashSet<Foo>();
...
}
Keeping the table as is, with the fk to the parent?
I've tried this but I keep getting the same error, fk restriction violated.
Edit 2
Finally solved with:
#Entity
class Foo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "PARENT_ID")
private Foo parentNode;
#OneToMany(mappedBy = "parentNode", cascade = CascadeType.REMOVE)
private Set<Foo> childs = new LinkedHashSet<Foo>();
...
}
This #OneToMany is needed even if we do the mapping in our BBDD by refering just the parent id.
Now when we delete a Foo with childs, it's childs will be deleted as well.
Thanks for your time and good advices!
Look at orphanRemoval option:
#OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true)
Here is complete explication about CascadeType.REMOVE and orphanRemoval.
Good luck!
Relationships in JPA are always unidirectional, unless you associate the parent with the child in both directions. Cascading REMOVE operations from the parent to the child will require a relation from the parent to the child (not just the opposite).
So here you need to change unidirectional relationship to bi-directional.
for more details refer this link.
I've been searching over the web to find out a solution for this. It seems nobody has the answer... I start thinking i'm in wrong way adressing the problem.
Let's see if i can explain easy.
Im developing a contract maintenance. (table: contrat_mercan). For the contract, we will select a category (table: categoria), each category has qualities (table: calidad) in relation 1 - N (relationship table categoria_calidad).
This qualities must have a value for each contract where the category is selected, so I created a table to cover this relationship: contrato_categoria_calidad.
#Entity
#Table(name = "contrato_categoria_calidad")
public class ContratoCategoriaCalidad implements Serializable{
// Constants --------------------------------------------------------
private static final long serialVersionUID = -1821053251702048097L;
// Fields -----------------------------------------------------------
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CCC_ID")
private int id;
#Column(name = "CONTRAT_MERCAN_ID")
private int contratoId;
#Column(name = "CATEGORIA_ID")
private int categoriaId;
#Column(name = "CALIDAD_ID")
private int calidadId;
#Column(name = "VALOR")
private double valor;
.... getters/ setters
In this table I wanted to avoid having an Id, three fields are marked as FK in database and first attempts where with #JoinColumn in the three fields. But it does not worked for hibernate.
Anyway, now ContratoCategoriaCalidad is behaving okay as independent entity. But I will need to implement all maintenance, updates, deletes for each case manually... :(
What I really want, (and I think is a better practice) is a cascade when I saveOrUpdate the contract as the other entities do, but I don't find the way to make a List in contrat_mercan table.
This is working perfect for other relationships in same table:
#OneToOne
#JoinColumn(name="CONDICION")
private Condicion condicion;
#OneToMany (cascade = {CascadeType.ALL})
#JoinTable(
name="contrato_mercan_condicion",
joinColumns = #JoinColumn( name="CONTRATO_MERCAN_ID")
,inverseJoinColumns = #JoinColumn( name="CONDICION_ID")
)
private List<Condicion> condiciones;
But all my attempts to map this failed, what i want, is to have in my Java entity contrat_mercan a field like this:
private List<ContratoCategoriaCalidad> relacionContratoCategoriaCalidad;
not a real column in database, just representation of the relationship.
I found solutions to join multiple fields of the same table, here, and here, but not to make a relationship with 3 tables...
Any idea? Im doing something wrong? Maybe i must use intermediate table categoria_calidad to perform this?
Thanks!!
If you want to access a list of related ContratoCategoriaCalidad objects from Contrato entity you need to declare a relationship between those two entities using proper annotations.
In ContratoCategoriaCalidad class change field to:
#ManyToOne
#JoinColumn(name = "CONTRATO_ID")
private Contrato contrato;
In Contrato class add field:
#OneToMany(mappedBy = "contrato")
private List<ContratoCategoriaCalidad> relacionContratoCategoriaCalidad;
If you want to enable cascade updates and removals consider adding cascade = CascadeType.ALL and orphanRemoval = true attributes to #OneToMany annotation.
Hope this helps!
I've read some related questions but they are not exactly the same problem as mine.
I'm using JPA + Hibernate + Spring and I want to do something that I'm not sure if it is possible just with config.
I have my domain classes with a more or less complicated relation. There are many elements that are related with one element (like if it was a tree many elements are sons of one element).
Something like:
#Entity
class Foo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "PARENT_ID")
private Foo parentNode;
...
}
Which will get a table like:
Foo id parent_id
1
2 1
3 1
When I delete row with id = 1 I want to delete rows with id = 2 and id = 3 (it may be recursive, elements with parent_id = 2 and parent_id = 3 would be deleted as well).
For some restrictions I only can have the relation in son's side with the parent_id reference.
My question is: is it possible to do this with JPA or Hibernate configuration or do I need to do some recursive function to delete all children and all parents?
I've tried with:
#OneToMany(name = "PARENT_ID", cascade = CascadeType.REMOVE)
And I've read that maybe using Hibernate annotations.
If anyone can give me some clue I'm lost at this point.
Edit 1
Would it be possible to do like:
#Entity
class Foo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name="PARENT_ID")
private Foo parentNode;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "parentNode", cascade = CascadeType.REMOVE, orphanRemoval = true)
private Set<Foo> childs = new LinkedHashSet<Foo>();
...
}
Keeping the table as is, with the fk to the parent?
I've tried this but I keep getting the same error, fk restriction violated.
Edit 2
Finally solved with:
#Entity
class Foo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "PARENT_ID")
private Foo parentNode;
#OneToMany(mappedBy = "parentNode", cascade = CascadeType.REMOVE)
private Set<Foo> childs = new LinkedHashSet<Foo>();
...
}
This #OneToMany is needed even if we do the mapping in our BBDD by refering just the parent id.
Now when we delete a Foo with childs, it's childs will be deleted as well.
Thanks for your time and good advices!
Look at orphanRemoval option:
#OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true)
Here is complete explication about CascadeType.REMOVE and orphanRemoval.
Good luck!
Relationships in JPA are always unidirectional, unless you associate the parent with the child in both directions. Cascading REMOVE operations from the parent to the child will require a relation from the parent to the child (not just the opposite).
So here you need to change unidirectional relationship to bi-directional.
for more details refer this link.
I need some help with a JPA self referencing relationship. I think there is something that I have not defined correctly.
I have a JPA entity bean named ItemEntity. There are two types of items. Parent items and child items. The parent item can have many child items and the child item only has one parent item. So really this is a ManyToOne / OneToMany JPA self referencing relationship.
In my database the item table looks like this...
item_no,parent_item_no,item_description
111,null,This is my parent item
222,111,This is my child item
So in my java program when I call itemEntity.getChildren on item 111, I would expect to see 222 however I am getting null.
Here is how I have defined my JPA relationship...
#Entity(name = "stg_item")
public class ItemEntity implements java.io.Serializable {
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "itemid")
#TableGenerator(name = "itemid", table = "stg_items_sequence", allocationSize = 1)
private Long id;
#ManyToOne(fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "item_no", referencedColumnName = "parent_item_no")
private ItemEntity parent;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "parent")
private Collection<ItemEntity> children;
Can anyone tell me what I am doing wrong here?
The item entity has a #ManyToOne relationship with another one of my entities named stg_import_payload. Here is the named query I am using. Maybe I have to do something special with the named query?
"SELECT x "
+ " FROM stg_import_payload x "
+ " WHERE x.processedInd='N' "
+ " AND EXISTS (SELECT stg_item FROM stg_item stg_item WHERE stg_item.importPayload = x AND stg_item.processedInd='N') ";
Thanks.
Docs:
String javax.persistence.JoinColumn.referencedColumnName()
(Optional) The name of the column referenced by this foreign key column.
When used with entity relationship mappings other than the cases described here, the referenced column is in the table of the target entity.
When used with a unidirectional OneToMany foreign key mapping, the referenced column is in the table of the source entity.When used inside a JoinTable annotation, the referenced key column is in the entity table of the owning entity, or inverse entity if the join is part of the inverse join definition.
When used in a CollectionTable mapping, the referenced column is in the table of the entity containing the collection.
Default (only applies if single join column is being used): The same name as the primary key column of the referenced table.
You should change this:
#ManyToOne(fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "item_no", referencedColumnName = "parent_item_no")
private ItemEntity parent;
to
#ManyToOne(fetch = FetchType.LAZY, optional = true)
private ItemEntity parent;
It works for me
I have a class A{Set b .....} which holds references of class B as Set. It is one to many relationship.
Both class have sequencer in oracle. I put cascade to all in hibernate annotations. When i save class A, it gives me error that cannot insert null B.a_id . A-id is not nullable in my database. How can i persist this relationship.
This is a unidirectional relationship from A->B. a_id column in table B is not nullable. When hibernate tries to save class B, it not able to find value for a_id.
Well, did you try to make the JoinColumn non nullable?
#OneToMany
#Cascade({CascadeType.ALL})
#JoinColumn(name="A_ID", nullable=false)
private Set<B> b;
See also
Hibernate Core Reference Guide
6.2.1. Collection foreign keys
I ran into the same problem and solved it by using the mappedBy attribute of the #OneToMany annotation in Class A:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "m_a")
private Set<B> b;
Here, m_a is the field in Class B that refers to Class A:
#JoinColumn(name = "aId", nullable = false)
#ManyToOne
private A m_a;
This way, the #JoinColumn is only specified in one place, no duplicated code.