I have 2 classes that are connected by a bidirectional ManyToOne / OneToMany relationship:
Member in ClassA:
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "classA")
private List<ClassB> classBList = new ArrayList<ClassB>();
Member in ClassB:
#ManyToOne
#JoinColumn(name = "CLASSA_ID", referencedColumnName = "id")
private ClassA classA;
When I call classA.getClassBList().add(newClassB); a new DB entry for classB is created, but the DB column CLASSA_ID remains null.
of course all entities are defined in persistence.xml.
i appreciate any help, maybe it's just a little detail.
Thanks to bigGuy
My class looks like that now:
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "CLASSA_ID", referencedColumnName = "id")
private List<ClassB> classBList = new ArrayList<ClassB>();
#ManyToOne
private ClassA classA
The annotation #JoinColumn indicates that this entity is the owner of the relationship.
In your case, owner is ClassB.
So, you should use this line to create relationship:
newClassB.setClassA(classA);
If you want to create relationships with line
classA.getClassBList().add(newClassB);
make ClassA owner of relationship (move #JoinColumn to classA).
Related
I have a scenario like below.
Lets say EntityA has three nested entities EntityB, EntityC, EntityD. And all of EntityB, EntityC, EntityD has several nested entities inside them.
But while selecting for EntityA it selects the whole tree of nested entities. Whereas I want to fetch a specific branch. Lets say only EntityA, EntityB and all sub entities of EntityB are to be fetched leaving EntityC and EntityD back then I am not sure how to do that. As spring jpa brings all the nested objects back to me.
I am using below collection mapping.
#Entity
#Table(name = "customer_party_mapping")
#Data
public class CustomerPartyMappingEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "customer_id")
private Integer custmerId;
#Column(name = "orgtype_id")
private Integer orgTypeId;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "customer_party_mapping_id")
#Fetch(value = FetchMode.SUBSELECT)
private List<CustomerPartyBookingLocationEntity> customerPartyBookingLocation=new ArrayList<CustomerPartyBookingLocationEntity>();
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "customer_party_mapping_id")
#Fetch(value = FetchMode.SUBSELECT)
private List<CustomerPartyFieldMappingEntity> customerPartyFieldMappingEntity=new ArrayList<CustomerPartyFieldMappingEntity>();
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "customer_party_mapping_id",referencedColumnName="id")
#Fetch(value = FetchMode.SUBSELECT)
private List<CustomerPartyOtherDocumentEntity> otherDocumentsList=new
ArrayList<>();
#OneToOne( cascade={ CascadeType.PERSIST, CascadeType.MERGE })
#JoinColumn(name = "customer_name_screening_id", referencedColumnName="id")
private CustomerNameScreeningEntity customerNameScreeningEntity;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "customer_party_mapping_id")
#Fetch(value = FetchMode.SUBSELECT)
private List<CustomerDocInfoTrackingEntity> customerDocInfoTrackingList=new
ArrayList<CustomerDocInfoTrackingEntity>();
}
And I am calling
List<CustomerPartyMappingEntity> customerPartyMappingEntityList = customerPartyMappingRepository.findByCustmerId(customerid);
It gets all the nested mapped list of entities wheras I need only CustomerPartyMappingEntity and its list of customerPartyFieldMappingEntity nested object.
Any help will be appreciated.
First use FetchType.LAZY for nested entity.
Then you can use #EntityGraph to fetch nested entity by name and their nested entity using their name with . in the repository. You use to just specify the nested property in attributePaths like
#EntityGraph(attributePaths = {"customerPartyBookingLocation"})
And the nested property of customerPartyBookingLocation like
#EntityGraph(attributePaths = {"customerPartyFieldMappingEntity.subField"})
Example:
#EntityGraph(attributePaths = {"customerPartyBookingLocation", "customerPartyFieldMappingEntity.subField"})
List<CustomerPartyMappingEntity> findByCustmerId(Integer customerid);
Note: You can't use #EntityGraph with #Query annotation
If your entities are really setup correctly, see for instance the subselect example here and remove your EAGER (you are currently instructing hibernate to fetch all these fields upon entity initialization). It should work.
I have these two classes :
public class ClassA extends [...] implements [...] {
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = JOIN_TABLE_NAME,
joinColumns = #JoinColumn(name = COLUMN_REF_A, referencedColumnName = COLUMN_ID_A),
inverseJoinColumns = #JoinColumn(name = COLUMN_REF_B, referencedColumnName = COLUMN_ID_B))
private List<ClassB> fieldClassB;
}
public class ClassB extends [...] implements [...] {
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "fieldClassB", cascade = CascadeType.ALL)
private List<ClassA> fieldClassA;
}
When I delete ClassB (via the spring data jpa repository), Hibernate also deletes instances of ClassA, whereas I just want the rows in the JOIN_TABLE_NAME table to be deleted (the other issue is that, due to the cascade mode, deleting the ClassA entities also delete other ClassB referenced by these ClassA).
Is there any way to handle this without having to create the join entity and to replace the #ManyToMany annotations by #OneToMany referencing the new join entity ?
Cascade Remove in a manyToMany it's not only applied to the link table, but to the other side of the association as well.
So Cascade.ALL which inherit remove too is almost always a bad thing to have on a manyToMany as it ends up deleting things not only from association table.
What you want is to have add and remove method in your entities to do the work and keep both list synchronized:
public class ClassA extends [...] implements [...] {
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = JOIN_TABLE_NAME,
joinColumns = #JoinColumn(name = COLUMN_REF_A, referencedColumnName = COLUMN_ID_A),
inverseJoinColumns = #JoinColumn(name = COLUMN_REF_B, referencedColumnName = COLUMN_ID_B))
private List<ClassB> fieldClassB;
public void addClassB(ClassB b) {
fieldClassB.add(b);
b.fieldClassA().add(this);
}
public void removeClassB(ClassB b) {
fieldClassB.remove(b);
b.fieldClassA().remove(this);
}
}
There's an Entity Class 'A' (supposed to be a Person),There's another Entity Class 'B' (supposed to be a Contract).
Entity 'A' has a relation #OneToMany to Class 'B' ( a person can sign alot of contracts). Entity 'B' also has a relation #OneToMany to Class 'A' (a contract can have many person signing it).
In this case, there's gonna be 2 JoinTable in database, but actually they both are somehow the same.
Is there anyway that i make them just using One JoinTable?
tnx for any help!
Looks like a #ManyToMany relation to me...
in class Person
#ManyToMany
#JoinTable(name="PERS_CONTRACTS")
public Set<Contract> getContracts() { return contracts; }
in class Contract
#ManyToMany(mappedBy="contracts")
public Set<Person> getSigners() { return signers; }
By using two #OneToMany there is no JoinTable.
you can use #ManyToMany like this
#ManyToMany
#JoinTable(
name="AB",
joinColumns=#JoinColumn(name="A_ID", referencedColumnName="ID"),
inverseJoinColumns=#JoinColumn(name="B_ID", referencedColumnName="ID"))
private List<B> bS;
Its a kind of Many to Many relationships. So it need just one junction table like person_contract in database. It will contains columns like:
Person_id
Contract_id
where both person_id & contract_id will be a composite unique key.
In hibernate it will be:
1. In Person table
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "person_contract ", joinColumns = {
#JoinColumn(name = "person_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "contract_id",
nullable = false, updatable = false) })
public Set<Contract> contracts;
In Contract table
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "contracts")
public Set<Person> persons;
Situation:
You are complicating things here, the appropriate relationship between your Entities would be ManyToMany, because :
A person can sign many contracts.
And a contract can be signed by many persons.
And one JoinTable in this relationship is sufficient to give you all the requested details:
Who signed a given Contract.
Which Contracts have a Person signed.
Mapping:
So your mapping will be like this:
In your Person class:
#ManyToMany(mappedBy = "persons")
private Set<Contract> contracts= new HashSet<Contract>();
And in your Contract class:
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "PERSONS_CONTRACTS",
joinColumns = #JoinColumn(name = "CONTRACT_ID"),
inverseJoinColumns = #JoinColumn(name = "PERSON_ID")
)
private Set<Person> persons= new HashSet<Person>();
You can check this Hibernate Many-to-Many Association Annotations Example for further details.
Im trying to create to domain objects with a OneToOne relationship. A is the parent and B is the child.
I tried many different ways to cascade deletions from A to B but when i look a the database creation, it doesnt set up ON DELETE CASCADE.
Can someone see what im doing wrong
A:
#Entity
#Table(name = "financeaccountcurrencymapping")
public class FinanceAccountCurrencyMapping implements Serializable {
#Id
#GeneratedValue
private long id;
#OneToOne(cascade = CascadeType.ALL, optional = false, orphanRemoval = true, mappedBy = "financeAccountCurrencyMapping")
private FinanceAccount financeAccount;
I know that either CascadeType.ALL or orphanRemoval should do the trick, but they dont.
B:
#Entity
#Table(name = "financeaccount")
public class FinanceAccount implements Serializable {
#OneToOne(optional = true)
private FinanceAccountCurrencyMapping financeAccountCurrencyMapping;
Can someone see why it doesnt cascade deletions?
I solved it, but not with JPA
i set #OnDelete(action = OnDeleteAction.CASCADE) on the child
I am working with JPA and use Hibernate as a provider to my SQL Server database.
I need a many-to-many self referencing relation that has an additional column or even more additional columns.
That is my current code. I am getting exceptions by Hibernate:
#Entity
public class Person {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "person", fetch = FetchType.EAGER)
private Set<Relation> relations;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "relPerson", fetch = FetchType.EAGER)
private Set<Relation> inverseRelations;
}
#Entity
public class Relation implements Serializable {
#Id
#ManyToOne(cascade = CascadeType.ALL, optional = false, fetch = FetchType.EAGER)
#PrimaryKeyJoinColumn(name = "PersonID", referencedColumnName = "id")
private Person person;
#Id
#ManyToOne(cascade = CascadeType.ALL, optional = false, fetch = FetchType.EAGER)
#PrimaryKeyJoinColumn(name = "RelPersonId", referencedColumnName = "id")
private Person relPerson;
}
During runtime i get an exception from hibernate:
org.hibernate.TransientObjectException: object references an unsaved transient instance
Is there any way to implement this a little bit more intelligent and nicely?? Without getting that exception.
Thanks,
ihrigb
If an object not associated with a Hibernate Session, the object will be Transient.
An instance of Relation list may be Transient(Normally, There is no identifier value for that instance) when you save Person.
Here is better way to understand object state.