Entity mapping using a non primary key column - java

I am using hibernate and Mysql in the java project for persistence.
I have two entities Transaction and Service. Transaction is having many to one relation to service.
I wanted to use a non primary column(SERVICE_CODE) of type VARCHAR from Service table as a foreign key in the Transaction table. But when I do so I get the following exception.
SQL Error: 1452, SQLState: 23000
Cannot add or update a child row: a foreign key constraint fails.
SERVICE_CODE is defined as non null and unique in database.
Following example works fine if I use primary key from Service table for mapping.
#Entity
#Table(name="Transaction")
public class Transaction {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="TRANSACTION_ID")
long transactionId;
#ManyToOne
#JoinColumn(name="SERVICE_CODE")
Service service;
}
#Entity
#Table(name="SERVICE")
public class Service {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="SERVICE_ID")
Long serviceId;
#Column(name="SERVICE_CODE")
String serviceCode;
}

As explained in this article, you should use the referencedColumnName attribute of the #JoinColumn annotation to specify the referenced column of the foreign key relationship.
#ManyToOne
#JoinColumn(name="SERVICE_CODE", referencedColumnName="SERVICE_CODE")
Service service;
With this modification the DDL is generated correctly like this:
alter table Transaction
add constraint FK_5k37nrtsvi22y2jhsde903ps9
foreign key (SERVICE_CODE)
references SERVICE (SERVICE_CODE);
and with your original code like this (it references primary key of the SERVICE table instead of the SERVICE_CODE column):
alter table Transaction
add constraint FK_5k37nrtsvi22y2jhsde903ps9
foreign key (SERVICE_CODE)
references SERVICE;

Related

Create an Entity Class with two foreign keys - Spring JPA

How can i create entity class for the below table which has two foreign keys of two different tables.
CREATE TABLE `flights_info` (
`airline_id` bigint(20) NOT NULL,
`flight_infoid` bigint(20) NOT NULL,
UNIQUE INDEX `UK_mnghyk14c0ufcb2gs2k6fab40`(`flight_infoid`) ,
INDEX `FKm5m2579nqtr1wele0bimvme8m`(`airline_id`) ,
CONSTRAINT `FKlda61sltnw69kxw7b0gx6sj5s` FOREIGN KEY (`flight_infoid`) REFERENCES `flight_info` (`flight_infoid`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `FKm5m2579nqtr1wele0bimvme8m` FOREIGN KEY (`airline_id`) REFERENCES `airline_info` (`airline_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
);
my entity class:
#Entity
public class FlightsInfo {
#Id
#JoinTable(name="AirlineInfo", joinColumns=#JoinColumn(name="airline_id"))
private AirlineInfo airline_id;
#OneToOne
#JoinColumn(name="flight_infoid")
private FlightInfo flight_infoid;
}
The problem is that your table does not have a primary key. So it's hard to point the #Id annotation at the right column. JPA however accepts tables without PKs as long as you have a unique column: https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#No_Primary_Key
Luckily you have a unique constraint on the flight_infoid column, so there you should try to point your #Id annotation.

How to set the constraint name of a #OneToOne mapping?

#OneToOne
private AnyEntity entity;
hibernate will create a mapping as follows:
CONSTRAINT fk_kcn86scsc0pasdasdngmrqc5i0 FOREIGN KEY (text_id)
REFERENCES some_table (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
Question: how can I set the constraint name explicit from within java?
I cannot introduce a bidirectional mapping, as the AnyEntity class will be used in multiple other #Entity classes.
You can use #ForeignKey annotation.
#ForeignKey(name="constraint_name")

Hibernate: Issue with OnDelete Annotation

Hello
I have the following two entities
#Entity
public class DocumentCollection {
#Id
#GeneratedValue
private Long id;
#OneToMany(targetEntity=Document.class,mappedBy="documentCollection",cascade=javax.persistence.CascadeType.ALL)
#OnDelete(action = OnDeleteAction.CASCADE)
#Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Document> documents;
...
}
And:
#Entity
public class Document {
#Id
#GeneratedValue
private Long id;
#ManyToOne
private DocumentCollection documentCollection;
...
}
When a DocumentCollection gets deleted, all referenced documents should be deleted too.
But I'm getting this error:
Cannot delete or update a parent row: a foreign key constraint fails (`tms_db`.`document`, CONSTRAINT `FK3737353BEB85533C` FOREIGN KEY (`documentCollection_id`) REFERENCES `documentcollection` (`id`))
I also tried putting the #OnDelete Annotation in the document class but didn't work.
So what am I missing? For your information, I'am using Hibernate 3.6.0.Final.
UPDATE: I did a mysql schema dump and noticed that there is no ON DELETE CASCADE statement in the document table schema. Hibernate only generates the foreign key constraints, which leads to the mentioned error. Has anybody an idea why hibernate does NOT generate the "ON DELETE CASCADE" statement?
Hope, somebody can help me
thx
#OnDelete annotation affects the way Hibernate generates database schema. If your schema is not generated by Hibernate, or haven't been updated after adding this annotation, it wouldn't work correctly.
If you want to use manually created database schema with #OnDelete(action = OnDeleteAction.CASCADE), you should manually define foreign key constraint in your schema as on delete cascade.

Deleting JPA object fails due to foreign key constraints?

Why would the following query fail due to a foreign key constraint? There is no other way for me to delete the associated data that I am aware of.
Query query=em.createQuery("DELETE FROM Person");
query.executeUpdate();
em.getTransaction().commit();
The I believe the offending relationship causing the problem is the activationKey field:
2029 [main] ERROR org.hibernate.util.JDBCExceptionReporter - integrity
constraint violation: foreign key no action; FKCEC6E942485388AB
table: ACTIVATION_KEY
This is what I have now:
#Entity
#Table(name="person")
public class Person implements Comparable<Person> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private long id = 0;
#ElementCollection
#Column(name = "activation_key")
#CollectionTable(name = "activation_key")
private Set<String> activationKey = new HashSet<String>();
}
Why would the following query fail due to a foreign key constraint?
It looks like your bulk delete query is not deleting the entries from the collection table, hence the FK constraint violation.
And while the JPA spec explicitly writes that a bulk delete is not cascaded to related entities:
4.10 Bulk Update and Delete Operations
...
A delete operation only applies to
entities of the specified class and
its subclasses. It does not cascade to
related entities.
That's not exactly your case and I think that what you want to do should be supported.
You're probably facing one of the limitation of Hibernate's bulk delete, see for example:
HHH-3337 - Hibernate disregards #JoinTable when generating bulk UPDATE/DELETE for a self-joined entity
HHH-1917 - Bulk Delete on the owning side of a ManyToMany relation needs to delete corresponding rows from the JoinTable
I suggest raising an issue.
Workaround: use native queries to delete the collection table and then the entity table.

Why does not jpa2/eclipselink generate on delete cascade SQL?

#Entity
public class MUser implements Serializable, MemoEntity {
private static final long serialVersionUID = 1L;
#Id
private String email;
#OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
private Set<Meaning> mengs = new HashSet<Meaning>();
Shouldn't this mean that I get the constraint with a "on delete cascade"?
This is what gets generated instead:
CREATE TABLE MUSER_MEANING (MUser_EMAIL VARCHAR(255) NOT NULL, mengs_OBJID INTEGER NOT NULL, PRIMARY KEY (MUser_EMAIL, mengs_OBJID))
CREATE TABLE MUSER_MEANING (MUser_EMAIL VARCHAR(255) NOT NULL, mengs_OBJID INTEGER NOT NULL, PRIMARY KEY (MUser_EMAIL, mengs_OBJID))
ALTER TABLE MEANING ADD CONSTRAINT MEANING_USR_EMAIL FOREIGN KEY (USR_EMAIL) REFERENCES MUSER (EMAIL)
ALTER TABLE MUSER_MEANING ADD CONSTRAINT MSRMEANINGMsrEMAIL FOREIGN KEY (MUser_EMAIL) REFERENCES MUSER (EMAIL)
I'm trying to make it as such that deleting a MUser deletes all Meanings associated to it.
Why does not jpa2/eclipselink generate on delete cascade SQL?
Because that's not how things work. Specifying a cascade=REMOVE means that the remove operation will be cascaded to entities by the JPA provider, not at the database level using a constraint.
Some providers do have extensions to use a cascade delete constraint at the database level instead of the regular mechanism. For example with Hibernate, you can specify:
#OnDelete(action=OnDeleteAction.CASCADE) on joined subclasses: use a SQL cascade delete on deletion instead of the regular Hibernate mechanism.
But I don't know if EclipseLink has something equivalent.
References
JPA 2.0 Specification
Section 3.2.3 "Removal"
Hibernate Annotations Reference Guide
2.4. Hibernate Annotation Extensions

Categories

Resources