JPA: Give a name to a Foreign Key on DB? - annotations

I have a simple questions. How can I give a name to the Foreign Key relations that arise from the # ManyToOne annotation ?

With JPA 2.1 you can just do this with the foreignKey annotation:
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
#ManyToOne
#JoinColumn(name = "company_id", nullable = false, foreignKey = #ForeignKey(name="FK_COMPANY__ROUTE"))
private Company company;
Do not confuse with the deprecated hibernate equivalent

As of JPA 2.1 it is possible to define foreign keys via #ForeignKey annotation.
Unfortunately, it is not very useful if you only need to change the name. If you specify custom name of the FK, you also have to specify SQL definition of the FK. That is at least the way it works in EclipseLink 2.5.0.

If you are interested in naming the column used in the foreign key, one may specify the name of the column used to create the foreign key, using the #JoinColumn annotation along with the #ManyToOne annotation. The value of the name attribute of the #JoinColumn annotation is used by the JPA provider to map the column name in the table to the entity's attribute.
However, the name of the foreign key constraint created itself cannot be configured. At the time of writing this, it is not possible to specify the name of the foreign key constraint using a JPA annotation or configuration parameter in the OR mapping files. If you need to change the name of the foreign key constraint, then you must create the DDL statement yourself, instead of relying on the JPA provider to do this.

I think #ForeignKey doesn't work with #JoinTables or I don't know how to set custom names by this, I have tried it on #JoinTable->foreignKey and #JoinColumn->foreignKey

Related

How JPA knows the foreign key field from a mappedBy attribute?

In this example here
I understand what the mappedBy attribute is doing. It is telling JPA that the foreign key exists in Users table. But the foreign key in db is a field, but here they are designating a whole object
BillingInfo
as foreign key. How does JPA know which field inside BillingInfo object serves as foreign key?
mappedBy = "billingInfo" doesn't say where the foreign key is. It's telling Hibernate that the annotated field (user) constitutes the inverse side of a bidirectional association, and that the owning side of this association is the field User.billingInfo.
Hibernate thus looks how the User.billingInfo is mapped to know how this bidirectional association must be mapped.
In this case, the only annotation on User.billingInfo is #OneToOne. Since that doesn't say how the association is mapped, the defaults specified in the JPS specification will apply, and, IIRC, a join column named "billingInfo_id" will be used.

JPA 2 one to many - how does JPA infer column information?

I have a JPA2 (Hibernate) application which uses a MySQL database with only two tables. One table is called "companies" and the other table is called "employees". Between the two tables there is a one-to-many ralationship (1 company has many employees). The foreign-key column in table "employees" is called "company_id".
In my JPA2 Application I use the following annotations:
In the entity class "Company" I have the following annotation
#OneToMany(cascade = CascadeType.ALL)
private Collection<Employee> employees;
and in class Employee
#ManyToOne
private Company company;
How does JPA know what column it should use to determine all employees of a company. The annotations do not hold this information, but the application works.
Thank you
The ManyToOne side is missing the optional JoinColumn annotation, which in turn has the optional name attribute defaulting to:
The concatenation of the following: the name of the referencing relationship property or field of the referencing entity or embeddable class; "(underscore)"; the name of the referenced primary key column. If there is no such referencing relationship property or field in the entity, or if the join is for an element collection, the join column name is formed as the concatenation of the following: the name of the entity; "(underscore)"; the name of the referenced primary key column.
On the other side of the relationship, the OneToMany side, it's missing the mappedBy attribute (it should be equal to the name of the field that owns the relationship, in your case "company"). Javadoc says that this attribute is required unless the relationship is unidirectional, so there are chances that the JPA implementation you are using is assuming the relationship is unidirectional.

JPA 2 #JoinTable with keygeneration

Is there a way in JPA 2 to use a #JoinTable to generate a UUID key for the id of the row? I do not want to create new entity for this table (even if that would solve the problem) and I do not want to create it from the DB.
#ManyToMany
#JoinTable(name="Exams_Questions", schema="relation",
joinColumns = #JoinColumn(name="examId", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="questionId", referencedColumnName = "id"))
private List<Question> questions = new ArrayList<Question>();
db table
CREATE TABLE [relation].[Exams_Questions](
[id] [uniqueidentifier] PRIMARY KEY NOT NULL,
[examId] [uniqueidentifier] NOT NULL,
[questionId] [uniqueidentifier] NOT NULL,
Not sure exactly what the question is, but let me try a response.
For your first sentence alone, I would say "Yes" and "Possibly":
You'll need a separate #Entity class for the Question, and in that class you'd specify the mapping for id.
There is no way using spec JPA to specify auto-generation of a UUID value for a column. There are ways using OpenJPA and Hibernate. EclipseLink will allow you to create a custom generator for this purpose, and their example is, in fact, for a UUID.
If you'd like to expose properties of the join-table OR otherwise have JPA manage them (i.e. the id on the Exams_Questions table), then see this external link (found on this answer). You'll end up with #OneToMany relations from Exam/Question entities to the join table, and #ManyToOne relations from the join table to Exam/Question entities.
Exposing the join table as an entity will let you manage a separate key (uuid). If you don't need the uuid primary key, then don't do this - it's not necessary to solve the problem, as the examId/questionId combination is unique.

JPA SortedMap mapping - avoid two columns with keys

I have two classes, CalculatedValue and Price. Price has map of CalculatedValue. Each CalculableValue instance has name, value and couple of other fields.
Here is mapping I use to describe a dependency between Price and the CV:
#OneToMany(
cascade = CascadeType.ALL,
fetch = FetchType.EAGER
)
#JoinColumn(name = "priceId")
private Map<String, CalculatedValue> calculatedValues =
new TreeMap<String, CalculatedValue>();
No join table, just mapping by priceId column which refers to Price unique Id.
Here is how generated table looks like:
CREATE TABLE PUBLIC.CALCULATEDVALUE (
UNIQUEID BIGINT NOT NULL,
KEY VARCHAR(2147483647) NOT NULL,
PRICEID BIGINT,
VALUE DOUBLE NOT NULL,
CALCULATEDVALUES_KEY VARCHAR(2147483647),
PRIMARY KEY (UNIQUEID)
);
ALTER TABLE PUBLIC.CALCULATEDVALUE
ADD FOREIGN KEY (PRICEID)
REFERENCES TEST.PUBLIC.PRICE (UNIQUEID);
Everything is working, but I want to know if it possible to to this:
Avoid automatic "CALCULATEDVALUES_KEY" column creation. I already have this value stored in KEY column and it would be nice to avoid duplication and somehow give a hint to JPA.
Trigger cascade delete of calculable value for each removed price (in case I'm running SQL delete statement)
Will such mapping work in case I'll use Date as a key? Not for this particular field, but for a bunch of other ones it will be useful. Assuming the same OneToMany relationship.
Thank you in advance!
PS. I'm using latest version of EclipseLink & H2 as database.
PPS. Didn't want to store the calculable values in array since I need to often find it buy key in Java.
For info on Maps see,
http://en.wikibooks.org/wiki/Java_Persistence/OneToMany
and,
http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Maps
and,
http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_cascadeondelete.htm#CIABIIEB
A few issues:
EclipseLink will use Hashtable by default for Map, if you want it to use TreeMap you need to define the field as TreeMap.
Do not give a #JoinColumn on a #OneToMany, this is only supported for advanced unidirectional #OneToMany, a normal #OneToMany should use a mappedBy and have an inverse #ManyToOne in the target entity. (this will fix your issue of the duplicate foreign key).
You need to specify the #MapKey for a map, otherwise it defaults to the id, which seems to be an integer here, not a string.
You can use #CascadeOnDelete in EclipseLink to cascade a delete on the database.

JPA 2.0 Foreign Key Constraint

I have simple OneToOne relationship:
Data <-> TherapyResult
I would like to express the following constraints
with JPA.
If a Data entity gets removed the associated TherapyResult should be delete,too
If a TherapyResult entity gets removed the associated Data entity should remain in the db
The first constraint is really easy with JPA as I can add CascadingType.REMOVE
#OneToOne(cascade = { CascadeType.REMOVE, CascadeType.REFRESH })
private TherapyResult therapyResult;
For the second constraint I would like to add something like
#JoinColumn(columnDefinition = "DATA_ID BIGINT CONSTRAINT THERAPYRESULTDTAID FOREIGN KEY (DATA_ID) REFERENCES DATA (ID) ON DELETE SET NULL")
However this does not work. OpenJPA seems to have something similiar, but I want to use JPA 2.0 and EclipseLink. OpenJPA ForeignKey.
Another solution would be using #PreRemove described here, which works but looks a bit "none-best-practices" to me. However just a feeling.
My setup is:
Eclipse 3.7.1
EclipseLink 2.3
Apache Derby 10.8.3 and/or HSQLDB
any help is appreciated,
Muki
You can't use pure JPA to specify foreign keys ... that spec doesn't include the ability. JDO is the only standard with the ability to define FKs. You have to use implementation specifics, or just define the schema yourself and let the JPA impl run on it.
If you have a foreign key from Data to TherapyResult, and Data is the owner of the association, then
removing the Data will delete the TherapyResult automatically if cascade is set to REMOVE
you just need to set the therapyResult field to null and then delete the TherapyResult to have what you need. Another option is to set orphanRemoval to true, in which case setting the therapyResult field to null is sufficient to remove it from the database
If you have a foreign key from TherapyResult to Data, and TherapyResult is the owner of the association, then
removing the Data will delete the TherapyResult automatically if cascade is set to REMOVE on the Data.therapyResult field.
removing the TherapyResult will leave the Data in the DB provided the cascade is not set to REMOVE on the TherapyResult.data field