When saving a bi-directional #OneToOne mapping, is hibernate supposed to make a record on both tables?
I have a table interview with column applicant_id that references applicant table with field interview_id and vice versa, the columns being the FKs.
When creating a column by executing session.save(theInterview) is hibernate supposed to create a record in applicant table applicant_id? Do I need to update the existing record myself or am I doing things wrong?
Edit
Just was working on my JSP file and noticed that I could see that the reference exists on the applicant too. But the query on the DB shows the field empty?
Hibernate Mapping
#OneToOne(mappedBy="applicant_id", cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "interview_id")
private Interview interview_id;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "applicant_id", nullable=false)
private Applicant applicant_id;
Interview_id column on an applicant after recording an interview instance.
Can you provide your Hibernate mapping? What your asking about is Cascade, i.e. should Hibernate cascade save of the Applicant. That depends entirely on whether Hibernate has been instructed to cascade save on the relationship.
Related
I have a problem with using a OneToMany-Mapping with Hibernate that was working in version 4.3.8.Final but is not with version 5.4.2.Final .
When I query multiple entities from the db that have the same entries in a list that is mapped with OneToMany and then try to update those entities, hibernate throws the following exception even though I do not update any entries from the mapped relation: "Found shared reference to a collection: de.Artikel.filialeLager; nested exception is org.hibernate.HibernateException: Found shared reference to a collection: de.Artikel.filialeLager"
Here is my mapping, that was working fine with version 4.3.8.Final of Hibernate but is not anymore with 5.4.2.Final.:
#OneToMany(fetch = LAZY)
#JoinColumn(name = "SOME_ID", referencedColumnName="SOME_ID", insertable = false, updatable = false)
private List<filialeLager> filialeLager;
It seems to have a unidirectional relationship but is adding a reference column for a two-way relationship
The name of the column referenced by this foreign key column. When
used with entity relationship mappings other than the cases described
below, 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 Join- Table 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 collection table
mapping, the referenced column is in the table of the entity
containing the collection.
You should have something similar to this:
#OneToMany(fetch = LAZY)
#JoinColumn(name = "SOME_ID", insertable = false, updatable = false)
private List<filialeLager> filialeLager;
The problem is I need to select an object from database which has a join column inside, and I need the Id of that foreign object. But hibernate joins those two tables or if in lazy mode , It queries again on my database.
How do I access that Id with no other join or query than the primary select query.
Note that I am using Hibernate version +5 and I want an approach via JPA CriteriaBuilder.
Thank you in advance.
You can map the foreign key to the entity twice in this case, one for actual ORM and another for getting the FK without actually firing a new query.
public class Answer {
#JoinColumn(name = "question_id")
#ManyToOne(targetEntity = Question.class, fetch = FetchType.LAZY)
private Question question;
#Column(name = "question_id", insertable = false, updatable = false)
private Long questionId;
}
Here question_id is present in the answer table.
This way that foreign key will be already available in the result of the first query(in the questionId field) and the new query won't be fired for getting the FK value.
I have these two entities: Hotel, HotelPhoto
And the following relationship:
Hotel
#OneToMany(fetch = FetchType.EAGER, mappedBy="idHotel")
#OnDelete(action = OnDeleteAction.CASCADE)
public Set<HotelPhoto> getHotelPhotos() {
return hotelPhotos;
}
When I run this code the hibernate is creating a foreign key restriction with RESTRICT on delete and on update. I would like to have a CASCADE restriction on delete and on update. Is there a way to do that and avoid automatically creating a RESTRICT restriction?
I've got the following entity:
#Entity
#Table(name = "ONE")
#SecondaryTable(name = "VIEW_TWO", pkJoinColumns = #PrimaryKeyJoinColumn(name="ONE_ID"))
public class CpBracket {
#Id
private Long id;
#Column(name="progress", table="VIEW_TWO", updatable = false, insertable = false)
private int progress = 0;
(...)
}
As you see, this entity uses table ONE and (read only) view VIEW_TWO. When I'm persisting the entity, hibernate is performing insert into view:
insert into VIEW_TWO (ONE_ID) values (?)
It is ignoring the non-updatable and non-insertable column progress (that's good) and it is still trying to insert value of ONE_ID column. As far as I know, the annotation #PrimaryKeyJoinColumn marks selected column as insertable=false and updatable=false.
How can I prevent hibernate from inserting rows into secondary table (view)?
As far as I know, the annotation #PrimaryKeyJoinColumn marks selected
column as insertable=false and updatable=false.
I do not believe this can be the case: how then do we get records inserted into the #SecondaryTable when it is an actual table rather than a view?
As neither #SecondaryTable or #PrimarykeyJoinColumn have a means to prevent insert then it would appear that your original solution is not going to work and an alternative is required.
One option is to map VIEW_TWO as an #Entity and link to your class CPBracket as a #OneToOne relationship with cascade options set to none.
#Entity
#Table(name ="VIEW_TWO")
private CpBracketSummaryData(){
}
#Entity
#Table(name = "ONE")
public class CpBracket {
#OneToOne
#PrimaryKeyJoinColumn
private CPBracketSummaryData summaryData;
public int getSomeValue(){
return summaryData.getSomeValue();
}
}
The second option would be to use the non JPA compliant, Hibernate specific #Formula annotation.
#Entity
#Table(name = "ONE")
public class CpBracket {
#Formula("native sql query")
private int someValue;
}
Update October 2016
I have revisited this in both Hibernate 4.3.10.Final and 5.1.0.Final and it is possible to have the view as a #SecondaryTable without the insert: if you have the correct mappings.
Scenario 1
Load an entity for edit and do not touch any fields mapped to the secondary table. No update is issued to the secondary table
Scenario 2
Create and save a new entity and do not set any fields mapped to the secondary table. No insert is issued for the secondary table
Scenario 3
Create or update an entity including a field mapped to a secondary table and where this field is marked as insertable = false and updateable = false. An insert is made to the secondary table only for the ID field -the behaviour reported in the original question.
The issue with the mapping in the original question is the fact that the secondary table field is a primitive type and therefore when saving a new entity Hibernate does think a record has to be written to the secondary table with a value of zero.
#Column(name="progress", table="VIEW_TWO", updatable = false, insertable = false)
private int progress = 0;
The solution then is to replace primitives with the corresponding wrapper types and leave them as null. Then when saving a new record there is nothing to write to the secondary table and no insert will be made:
#Column(name="progress", table="VIEW_TWO")
private Integer progress;
I solved a similar problem with #SecondaryTable, which was a database view. So maybe it will help someone else.
The problem was on cascade delete to #SecondaryTable, when record from primary table was deleted.
As a solution, I implemented RULE on view for delete
CREATE RULE on_delete AS ON DELETE TO my_view DO INSTEAD(
select 1;
)
Similar solution can be used for INSERT and UPDATE operation on view.
I have an entity named 'Department' and another entity named 'student'. I know the department will have many students and there shoulld be relation between these two tables in database. But in my project, the DB tables are already there and there is no relation (foreign key) between department and student tables.
In entity class, student.java , there is a relation written as,
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = 'DeptId', nullable = false, insertable = false, updatable = false)
Department department
I am confused about this existing code.
When I wrote a test, I am fetching the department from DB by deptId and set the student entity as,
student.setDepartment(department);
This doesn't populate the DB column 'DEPTID' in student table.
Since there's no student collection in Department, I cannot set the student as,
department.addStudents(student);
I am not sure whether we can insist a #ManyToOne relation without a relation between the tables in DB.
Please let me know how I can fix this issue so that the 'DEPTID' column in student table is populated with the correct data.
Thanks in advance,
BS
you r having
#JoinColumn(name = 'DeptId', nullable = false, insertable = false, updatable = false)
instead why dont you try
#JoinColumn(name = 'DeptId', nullable = false)
Hibernate wont check whether the mapping constraints that you are putting are valid at db level. It just assumes it is valid and executes queries based on that assumption.
Hi sorry for responding to your question so late but I think the reply could equally help another person. Now you said the tables existed already in the database, if they haven't yet got some data then I suggest you drop them, activate your Table Generation Strategy in your persistence.xml file to Create, in that case, it will recreate those tables with your desired relationship columns. Do not also forget to use the #OneToMany annotation on the Department.java class to indicate its capabilities of reception of many students. It is used together with the #ManyToOne