Hibernate throws error after migration (references on same collection) - java

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;

Related

Spring Boot joining two entities with invalid FK entries

I am mapping some Java classes using hibernate on a database that I have no write access for. One of the fields used as a FK between ClientEpisodes and Physician's has 6 rows that contain a -1 for the FK. THis is obviously an invalid FK, but I need to still join and simply ignore these Physicians and have a null physician.
I am joining the class using
#JoinColumn(name = "epi_phid1", referencedColumnName = "ph_id", foreignKey = #ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Physician physician;
I tried specifying NO_CONSTRAINT to see if it would ignore it then, but even still I get the following error:
javax.persistence.EntityNotFoundException: Unable to find private.package.info.Physician with id -1
Is there any way to tell Hibernate to ignore values that aren't valid such as the -1?
The #ForeignKey annotation with NO_CONSTRAINT value tells hibernate to not generate foreign keys, if schema generation is used. It doesn't have any effect on the internal entity validation in the JPA framework.
There is a hibernate specific #NotFound annotation which you could use:
#JoinColumn(name = "epi_phid1", referencedColumnName = "ph_id")
#NotFound(action = NotFoundAction.IGNORE)
private Physician physician;
However be advised that if you use this in a #OneToMany or #ManyToMany annotation which maps a Collection, hibernate will fill the invalid/missing entities with null (so the list will contain null value(s)).

When Should I Use #JoinColumn or #JoinTable with JPA?

#JoinColumn gives an Entity a foreign key to another Entity whereas #JoinTable will list the relationship between all relationships between Entity A and Entity B. As far as I can tell, they both appear to do similar things. When should I use one or the other?
Let's say you have an entity A which has a #ManyToOne association ot an entity B
#JoinColumn will define the target table Foreign Key (e.g B_ID) while using the target Entity table (e.g. B).
#Entity
public class A {
private Long id;
#ManyToOne
#JoinColumn(name="B_ID")
private B b;
}
#JoinTable will use a separate table to hold the relationship between A and B.
#Entity
public class A {
private Long id;
#ManyToOne
#JoinTable(
name = "A_B",
joinColumns = #JoinColumn(name = "B_ID"),
inverseJoinColumns = #JoinColumn(name = "A_ID")
)
private B b;
}
This time neither A nor B contain any Foreign Key, because there's a separate table (e.g. A_B) to hold the association between A and B.
#JoinTable stores the id of both the table into a separate table while #JoinColumn stores id of the another table in a new column.
#JoinTable : This is the default type. Use this when you you need a more normalized database. ie. to reduce redundancy.
#JoinColumn : Use this for better performance as it does not need to join extra table.
one important difference: #JoinColumn always depends upon the context it is used:
If the join is for a OneToOne or ManyToOne mapping using a foreign key mapping strategy, the foreign key column is in the table of the
source entity or embeddable.
If the join is for a unidirectional OneToMany mapping using a foreign key mapping strategy, the foreign key is in the table of
the target entity.
If the join is for a ManyToMany mapping or for a OneToOne or bidirectional ManyToOne/OneToMany mapping using a join table, the
foreign key is in a join table.
If the join is for an element collection, the foreign key is in a collection table.

Read-only association with JPA OneToMany mapping

I have a transactional entity associated to another entity whereby the associated should not be updated in an case.
Eg. Case *-> User
Where a Case is owned by a User and reversely a User can have many associated Case.
The association is mapped using OneToMany and JoinColumn JPA annotations.
I have also tried marking the Trasactional annotation for User entity as readonly and also made the fetch methods Transient. But this doesnot seem to stop update on User if its state is changed.
Please help me a figure a way to declare a "read-only" association to User.
You can add updatable=falseon #JoinColumn annotation.
Furthermore you should not add a setter method for user in your Case entity and same for caseSet in your User entity. The getter getCaseSet in User entity should also return an unmodifiable collection:
public Set<Case> getCaseSet() {
return Collections.unmodifiableSet(caseSet);
}
The Column annotation and XML element defines insertable and updatable options. These allow for this column, or foreign key field to be omitted from the SQL INSERT or UPDATE statement. These can be used if constraints on the table prevent insert or update operations. They can also be used if multiple attributes map to the same database column, such as with a foreign key field through a ManyToOne and Id or Basic mapping. Setting both insertable and updatable to false, effectively mark the attribute as read-only.
In #OneToMany mapping, #JoinColumn annotation, add both updatable=false and insertable=false, then specify the cascade type as PERSIST instead of ALL
#OneToMany(cascade = CascadeType.PERSIST)
#JoinColumn(name = "<ReadOnlyTableName>", updatable = false, insertable = false)

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

How can I ask Hibernate to create an index on a foreign key (JoinColumn)?

Here is my model:
class User {
#CollectionOfElements
#JoinTable(name = "user_type", joinColumns = #JoinColumn(name = "user_id"))
#Column(name = "type", nullable = false)
private List<String> types = new ArrayList<String>();
}
As you can imagine there would be a table called "user_type", which has two columns, one is "user_id" and the other is "type".
When I use hbm2ddl to generate the ddls, I want to have this table, along with the foreign key constraint on "user_id".
However, there is no index for this column. How can I get hibernate to generate the index for me?
Try an #Index annotation.
#Index(name="user_type_index")
There is also an #IndexColumn annotation used with join tables, but it doesn't seem to actually create an index, but controls which field defines order in list semantics.
The #Index column in this context does seem to create an index on the join table.
I'm dealing with a similar issue and I've found that some dialects will automatically index foreign keys and others wont.
Hibernate Dialect class and all subclasses which do not override the getAddForeignKeyConstraintString method (Oracle, SQL Server, etc) will not create an index on the foreign key.
MySQLDialect overrides that method and adds an index to every foreign key

Categories