JPA 2 #JoinTable with keygeneration - jpa

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.

Related

JPA: Unidirectional one-to-many relationship with composite semi-shared primary key without join table

JPA:
How can I model the following in JPA:
a uni-directional one-to-many relationship
where the owning entity has a single-column application-determined primary key AND
where the child entity has a composite primary key AND
where one part of the child's primary key is the parent's primary key AND
avoiding JPA generating a join table.
Any ideas?
I figured out myself how to do this.
You need to annotate the foreign key in the owning entity with
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "myId", referencedColumnName = "parentId")
private List<ChildEntity> childEntity;
The primary key part in the child entity that is also the foreign key referencing the owning entity must not be annotated as being a foreign key, so e.g.:
#Id
private String parentId;
The usual rules concerning composite primary keys apply for the child class (primary key class annotated with #Embeddable etc.)
As user DN1 commented, the #JoinColumn annotation must be used, but it must be specified at the foreign reference in the owning class.
For some reason, you also must not use #PrimaryKeyJoinColumn instead of #JoinColumn, otherwise JPA will generate join tables.
Another challenge would be that the owning class's primary is also composite, but I haven't tried that.

Hibernate/JPA mapping OneToOne relation / Heritage

I'm building my entities, I want to know 2 things please :
1) I have for example a class named "Order" and a class named "Order_Details" , I want to make them OneToOne on both side , how can I make it?? (Same thing with Order and Order_Validation).
2) I created a class "User" and Inherited many classes ("Client"/"Manager"/"Accountant" ...) "Manager" is related to other classes ("Order" for example ) so my question is in the "Order" table should I put a relation with "User" or "Manager"?? (I don't have an ID in )
Thank you
About #2...
It depends. Are you planning on having different tables for them? If this is the case, then you should put the relationship in Manager.
1) For your first question
Order Table
#OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "order")
private OrderDetail orderDetail;
Order_details Table. ( It will have a order_id column in it)
#OneToOne(optional = false)
#JoinColumn(name = "ORDER_ID")
private Order order;
2) Depending on what you want to do.
I would recommend going with USER table and USER_TYPE table. If a user will always belong to only on user type, then have a USER_TYPE_D key in USER table. If not have a one-to-many table like USER_TYPE_MAP table. Regarding the actions a user type can take, have a ROLES reference table and a separate table called USER_TYPE_ROLES which maps what role a user can play. So in JPA, you can User, UserType, Roles, UserTypeRoles etc and do a one-to-one or one-to-many mapping accordingly.

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.

ON DELETE SET NULL ON UPDATE SET NULL using JPA

How do i add ON DELETE SET NULL ON UPDATE SET NULL Constraint while creating the table using JPA . Below the entity definition
table
CREATE TABLE `node` (
`id` bigint(20) NOT NULL,
`parentNode_id` bigint(20) default NULL,
PRIMARY KEY (`id`),
KEY `FK1EC1DD0F28AB6BA5` (`parentNode_id`),
CONSTRAINT `FK1EC1DD0F28AB6BA5` FOREIGN KEY (`parentNode_id`) REFERENCES `node` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
#Entity
public class Node {
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "NodeSequence")
private long id;
#ManyToOne(cascade=CascadeType.REMOVE)
#JoinColumn(name = "parentNode_id", nullable = true)
protected Node parentNode = null;
}
It is a bad idea to use the JPA schema generator for this purpose. It is almost always preferable to have DDL scripts that are hand-coded and placed under version control, to manage your database.
Also, setting foreign key values to null via database constraints, will only result in your persistence context having dirty values, unless the JPA provider is aware of the foreign key constraints in the database, and consciously updates the corresponding values in the persistence context to null.
Also, it is unlikely that JPA schema generators support this feature. For instance, Hibernate does not support this yet, and there are multiple feature requests that have been raised, and none of them have been resolved. EclipseLink also does not appear to support this feature.

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

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