join table on Cascaded model not updated - java

I have 2 entity classes (Class A and Class B) mapped to database tables. They are cascaded so that saving object of class A would reflect change in table concerned with Class B as well. Now I want to have a join table with primary key from Class B and primary key of new entity Class (Class C). I used standard hibernate #JoinTable annotation. But Join Table is not updated. Am I allowed to do so in hibernate?
Class A(Fieldvisit)
#OneToMany(mappedBy = "fieldVisitId")
#Cascade({CascadeType.SAVE_UPDATE,CascadeType.DELETE})
private Collection<Fieldvisitdetail> fieldvisitdetailCollection;
Class B(Fieldvisitdetail)
#JoinTable(name = "fieldvisitgeo",
joinColumns = {
#JoinColumn(name = "fieldVisitDetailId", referencedColumnName = "fieldVisitDetailId")},
inverseJoinColumns = {
#JoinColumn(name = "geoId", referencedColumnName = "geoId")})
#ManyToMany(mappedBy = "fieldvisitdetailCollection", cascade = CascadeType.ALL)
private Set<Geo> geoId=new HashSet<Geo>();
Class C (Geo)
#ManyToMany(cascade = CascadeType.ALL)
private Set<Fieldvisitdetail> fieldvisitdetailCollection= new HashSet<Fieldvisitdetail>();
Code for Saving to database
public void addFieldVisit(Fieldvisit visitReportInfo){
getSessionFactory().getCurrentSession().save(visitReportInfo);
}

Related

Spring Data Jpa - ManyToMany - delete entities of the join table

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);
}
}

How to do One to One association in hibernate with foreign key and join table and unidirectional

I wish to have a one to one association with a join table in unidirectional way. -
Tables :
A (A_id, D_id, A_Data)
B (A_id, C_id) // Join table just contain relation between A and C
C (C_id, C_Data)
Class A {
.
.
#OneToOne(cascade = CascadeType.ALL)
#JoinTable(name = "B",
joinColumns = #JoinColumn(name = "A_id", referencedColumnName = "A_id"),
inverseJoinColumns = #JoinColumn(name = "C_id", referencedColumnName = "C_id"))
private C c;
}
I am using hibernate with jpa 2.0.
Entity D is not important in the model hence ignored.
I only wish to read data ,hence insert/update/delete use cases should not be concern, but one can suggest best practice in that case also.
This setup does not work. Can some one suggest how to do it in correct way?
It gives following exception
org.hibernate.MappingException: Unable to find column with logical name: A_id in org.hibernate.mapping.Table(A) and its related supertables and secondary tables
In order to get your desired schema:
// Given the following C entity
#Entity
public class C {
#Id
#Column(name = "C_ID")
private long id;
private String C_Data;
//...
}
// A Entity should be
#Entity
public class A {
#Id
#Column(name = "A_ID")
private long id;
private String A_Data;
#OneToOne(cascade = CascadeType.ALL )
#JoinTable(name = "B", joinColumns = #JoinColumn(name = "A_id"), inverseJoinColumns = #JoinColumn(name = "C_id", unique = true))
private C c;
//...
}
I've omitted referencedColumnName, so hibernate will map it to the entity primary key.
Note also that A_id column of B table will be the primary key.

JPA using one join table for two OneToMany entity

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.

Filter Rows in Join Table - Many to Many in Hibernate

I'm trying to implement a soft delete across my entire platform. Each table has a deleted_on column that will be used to filter out deleted rows.
This includes the join table that I have that's between my files and users. I haven't had any luck finding anything that could help. Right now my classes look like this
#Entity
public class File {
#ManyToMany
#JoinTable(
name = "file_user",
joinColumns = #JoinColumn(name = "file_id", referencedColumnName = "file_id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id")
)
private List<User> users;
// Constructor and other fields
}
User class:
#Entity
public class User {
#ManyToMany(mappedBy = "users")
private List<FileData> files = new ArrayList<>();
// Constructor and other fields
}
If it's possible I would like to be able to run the following code without filtering it in the business code
File file = fileRepository.findOne(fileKey);
file.getUsers().remove(user);
fileRepository.save(file);
if you are Hibernate as your JPA provider, then you can use the #Where annotation
#Entity
#Where(clause="deleted_on=1")
public class User {
#ManyToMany(mappedBy = "users")
private List<FileData> files = new ArrayList<>();
// Constructor and other fields
}
this will apply the where clause on all your queries with User Class
Additional Note:
you need to specify the #where clause again in all your relationships
#ManyToMany
#JoinTable(
name = "file_user",
joinColumns = #JoinColumn(name = "file_id", referencedColumnName = "file_id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id")
)
#Where(clause="deleted_on=1")
private List<User> users;

How to control JPA Column names in Map

The entity Construction
has following map:
#Column(name = "paper_FK")
#ManyToMany
#JoinTable(inverseForeignKey = #ForeignKey(name = "construction_FK"), joinColumns = #JoinColumn(name = "construction_FK", referencedColumnName = "construction_FK"), name = "ConstructionPaperTracks", inverseJoinColumns = #JoinColumn(name = "paper_FK"))
private HashMap<Integer, Paper> tracks_field = new HashMap<Integer, Paper>();
Due to my database design guidelines the table ConstructionPaperTracks
should have the columns construction_FK, position and paper_FK.
JPA works with construction_id, position and paper_id.
How can i specify the column names?
best regards
Heiko
I am not sure I understand "JPA works with construction_id, position and paper_id."
Anyway, I believe the mapping will be as below:
#Entity
public class Construction{
#Id
#Column(name = "construction_id")
//specify a generation strategy
private Long id;
#ManyToMany
#JoinTable(name = "ConstructionPaperTracks",
joinColumns = #JoinColumn(name = "construction_FK"),
inverseJoinColumns = #JoinColumn(name = "paper_FK"))
#MapKeyColumn(name = "position")
private HashMap<Integer, Paper> paper;
}
You need to specify the #MapKeyColumn, the documentation for which states that:
If the map key is for a ManyToMany entity relationship or for a
OneToMany entity relationship using a join table, the map key column
is in a join table
For the joinColumn and inverseJoinColumn the referencedColumn names will default to the primary key column of the referenced tables (construction_id, paper_id) so you don't have to specify these.

Categories

Resources