Collection isn't filled with OneToMany relationship - EclipseLink - java

I'm mapping a database (Oracle 11g) to JPA entities using EclipseLink. I have mapped almost every table to JPA objects but I've just found a problem:
In the \Curve\ entity I have the following fields:
#Id
#Column(name = "COD_CURVE")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq.gen")
#SequenceGenerator(name = "seq.gen.curve", sequenceName = "SEQCURVE", allocationSize = 1)
private long codCurve;
#Id
#Column(name = "FEC_HISTORIC")
#Temporal(javax.persistence.TemporalType.DATE)
private Date fecHistoric;
#OneToMany(mappedBy="codCurve", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Collection<CurveDetail> detailsCollection;
In the \CurveDetail\ entity I have this:
#ManyToOne
#JoinColumns({
#JoinColumn(name = "COD_CURVE", referencedColumnName = "COD_CURVE"),
#JoinColumn(name = "FEC_HISTORIC", referencedColumnName = "FEC_HISTORIC")
})
private Curve codCurve;
The problem is that when I query the \Curve\ entity, the details always are null, despite the fact that there is valid data in both tables. Checking the database I've noticed that there are no foreign key constraints in the \CurveDetail\ table, so I wonder ¿Are these constraints required to map the database correctly? I haven't tried to add the FK constraint myself because I'm not allowed to (have to ask a DBA to do it, and it'll take a week).
Thanks in advance!

Having a foreign key is not required.
Check the SQL that is generated by enabling logging ("eclipselink.logging.level"="finest")
Try executing the same SQL with the same database to see if the data exists.
Also ensure you are not corrupting the shared cache by inserting/updating an object with a null collection. You must maintain both sides of a bi-directional relationship. You could try disabling the cache to see if this is what you are doing.

As I know having a FK constraint is not mandatory. Once I had the same problem (but it was Oracle 9i) and found out that the name of Entity class should match the name of the table you want to map, and also JPA SQL and Hibernate HQL are both case sensitive so be careful in writing #Column tag.

Related

Hibernate FK reference issue

I have an entity with reference to another one by FK, at the same time I have a field mapped on the same column to have access right to the identifier, let's say
#Entity
#Table(name = "book")
public class Book {
#Id
#GeneratedValue
Long id;
#JoinColumn(name = "author_id")
#ManyToOne(fetch = FetchType.LAZY)
Author author;
#Column(name = "author_id", insertable = false, updatable = false)
Long authorId;
}
so, for now on select via JPA repository (findById for instance) the field of "authorId" is always null, but in actual database it exists and object of "author" fills correctly. Tested in the transaction and outside - result is the same.
About app - it is spring boot 2.2.8 with spring data
Are there any ideas where I can be wrong?
*Update: found the reason - all the found entities are cached somehow, after detaching them from persistence context all data loads as expected. Seems it's clear, but still cant get where interactions with these entities appear, obviously not in my tx - it is pretty small and simple. Never thought that neighboring transactions can affect cache this way =((

Hibernate select id of join column without join

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.

ManyToOne relation in Hibernate, not in Database

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

How do I create an index on join tables using Hibernate annotations?

I have a relationship as follows using Hibernate annotations, this is what I tried:
public class Job{
...
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "jobs_resource_locations")
#ForeignKey(name = "job_inputs_fk")
#Index(name="job_inputs_fk")
private List<FileSystemLocation> inputs;
This sort of thing works nicely on ManyToOne like so:
#ManyToOne
#JoinColumn(name = "service_call_id", referencedColumnName = "id")
#ForeignKey(name = "job_service_call_fk")
#Index(name = "job_service_call_fk")
private ServiceCall serviceCall;
I wanted to ensure that the foreign key gets indexed on PostgreSQL and that the schema looks similar on MySQL, hence the #ForeignKey and #Index with the same name (MySQL always creates an index with the same name as the FK).
I cannot create the index on the inverse side because FileSystemLocation is unaware of the relationship. Hence the JoinTable.
The former example fails since Hibernate finds no column in Job to index:
org.hibernate.MappingException: Unable to find logical column name from physical name null in table jobs
Does anyone know how to create indices on JoinTable foreign keys using Hibernate?
It's not exactly the answer you would like to receive, but this is the expected behavior. In other words: this is not supported. See the following JIRA for more details:
https://hibernate.atlassian.net/browse/HHH-4263

One-to-Many Unidirectional Parent-Child ID Cascade Save

When trying to save an ID from my parent class into a child class, I keep getting the error
"ERROR - Field 'parent_id' doesn't have a default value"
I have tried all types of mappings. I am using annotations.
Any help on this would be appreciated
Parent:
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(name="description")
private String description;
#OneToMany
#Cascade(value= {org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE})
#JoinColumn(name="parent_id")
private List<Child> children;
Child:
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(name="description")
private String description;
Thanks.
A late addition in case anyone ever runs into the same issue.
This entity here, when persisted using Hibernate 4.1.8, will cascade the FieldChangeentities, but will not fill the join column:
#Entity
public class Event {
//ID and other fields here
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "event_id")
private List<FieldChange<?>> fields = new ArrayList<FieldChange<?>>();
}
Neither does the insert statement set the event_id column, nor does it update the inserted entity after the fact - the event_id remains null and the relation is lost.
If, however, the #JoinColumn definition is changed like this:
#JoinColumn(name = "event_id", nullable = false)
, then the insert statement includes the event_id column like it should, and all is well.
This may only be a regression in this particular version of Hibernate, but maybe it helps someone.
In your case JPA provider to persist child object with its parent perform at least three queries on db. First two persist the objects by its own. The last one
update child object with the foreign key referencing parent. The second query fail because you have a NOT NULL constraint on the foreign key column. You have three options:
Remove NOT NULL constraint on foreign key in the child entity
Use bidirectional relationship
Change JPA provider to one which supports such cases.
You must have something wrong somewhere else because those mappings will work the way they are. They could be better, but they'll work. Specifically, all the #Column annotations are redundant and unnecessary, and as non sequitor noted, you should use the cascade property of JPA's #OneToMany instead of Hibernate's #Cascade. I've created a runnable example with the cleaned-up version of what you posted. If you have git and maven, you can run it with:
git clone git://github.com/zzantozz/testbed tmp
cd tmp
mvn -q compile exec:java \
-Dexec.mainClass=rds.hibernate.UnidirectionalManyToOneJoinColumn \
-pl hibernate-unidirectional-one-to-many-with-join-column
It creates a parent with two children, saves them, and then loads them and prints out the graph. The output is:
Creating parent with two children
Loading saved parent
Parent{description='parent', children=[Child{description='child 2'}, Child{description='child 1'}]}
Change your #OneToMany to #OneToMany(cascade=CascadeType.ALL) use JPA rather than the Hibernate extensions
My guess is that the #JoinColumn annotation needs a referencedColumnName assigned.
#JoinColumn(name = "parent_id", referencedColumnName = "id")

Categories