#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
Related
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.
I've been trying to deal with some problems regarding Flyway. My situation is the following: I have two Java classes, which I'd like to migrate as two schemas. Let's name them Table and CustomTable. My java classes look like:
#Entity
public class xtable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
//getters, setters, constructors
#Entity
public class CustomTable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String a;
private String b;
private String c;
//getters, setters, constructors
My application.properties:
spring.flyway.url=${env.var1}
spring.flyway.user=${env.var2}
spring.flyway.password=${env.var3}
spring.jpa.hibernate.ddl-auto=validate
//If I use create-drop, hibernate creates it, but after that the validation fails
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.logging.level.org.hibernate.SQL=debug
spring.jpa.show-sql=true
hibernate.temp.use_jdbc_metadata_defaults=true
spring.flyway.enabled=true
My build.gradle:
plugins {
id "org.flywaydb.flyway" version "5.2.4"
}
dependencies {
implementation 'org.flywaydb:flyway-core'
}
The situation is so weird, because it does not even work with the auto-generated SQL code, which I let the program create without flyway.
It looks like this:
create table custom_table (
id bigint not null,
a varchar(255),
b varchar(255),
c varchar(255),
xtable_id bigint,
primary key (id)
)
engine = InnoDB;
create table xtable (
id bigint not null,
name varchar(255),
xtable_id bigint,
primary key (id)
)
engine = InnoDB;
alter table custom_table
add constraint FKep6vooglihwraille12muox9 foreign key (xtable_id) references xtable (id);
alter table xtable
add constraint FK426q765pr4gv5wux6jaktafqk foreign key (custom_table_id) references custom_table (id);
I also don't understand why Hibernate creates one-one foreign key into each class, but the bigger problem is that I still get the error message
Schema-validation: missing table [custom_table]
I tried renaming custom_table to customtable (and also renaming the class in Java), but the error message was the same.
Have you ever met the same problem? Have you got any suggestions? I've been working on this problem for - at least - 2 days.
I looked for relevant - or seemingly identical - topics here, but I couldn't find a good solution.
Thank you.
Finally I got the problem. The problem was with inserting multiple foreign keys. (So these two lines):
alter table custom_table
add constraint FKep6vooglihwraille12muox9 foreign key (xtable_id) references xtable (id);
alter table xtable
add constraint FK426q765pr4gv5wux6jaktafqk foreign key (custom_table_id) references custom_table (id);
I couldn't figure out, though, the reason why Flyway couldn't handle this, but when I recreated the whole structure with the two tables and another one containing the proper ID's, doing exactly the same thing in the whole project, it worked.
In my project, an Admin (User) can set to receive scheduled emails about any User he chooses.
I need to have a database of the following design:
TABLE User (
UserId INT PRIMARY KEY AUTO_INCREMENT,
Email VARCHAR,
FirstName VARCHAR,
LastName VARCHAR
IsAdmin BOOL,
...
)
TABLE Email_Schedule (
ScheduleId INT PRIMARY KEY AUTO_INCREMENT, /* this is not necessary */
AdminId INT, /* could be replaced by a composite foreign primary keys */
UserId INT,
FOREIGN KEY (AdminId) REFERENCES User (UserId),
FOREIGN KEY (UserId) REFERENCES User (UserId)
)
The following code in my Java classes for JPA entity:
#Entity
public class Email_Schedule {
#Id
private int scheduleId;
#ManyToOne(targetEntity = User.class)
private List<User> admins = new LinkedList<>();
#ManyToOne(targetEntity = User.class)
private List<User> users = new LinkedList<>();
public Email_Schedule() {
super();
}
public Email_Schedule(User admin, User user) {
super();
this.admins.add(admin);
this.users.add(user);
}
// setters and getters...
generates a database of the following schema:
TABLE USER (
...
)
TABLE SCHEDULE (
ScheduleId INT PRIMARY KEY AUTO_INCREMENT
)
TABLE Email_Schedule (
ScheduleId INT,
Users INT,
Admins INT,
FOREIGN KEY (ScheduleId) REFERENCES SCHEDULE(ScheduleId),
FOREIGN KEY (Users) REFERENCES USER (UserId),
FOREIGN KEY (Admins) REFERENCES USER (UserId)
)
My question is why did it create a useless table for ScheduleId and referenced it from another table instead of just using it directly in Email_Schedule table?
The problem seems to be with the ScheduleId.. I tried not to use it by creating IdClass but I got different errors and wrong database designs.
EclipseLink is using TABLE for generating sequence for scheduleId.
This seems to be the default.
You can use a table for identifier generation on any database. This
strategy is completely portable across databases and will be
automatically generated for you when schema generation is enabled.
As per EclipseLink Documentation, you may have to use generation strategy of IDENTITY for scheduleId to avoid the TABLE appraoch.
#GeneratedValue(strategy=GenerationType.IDENTITY)
Note that if you use AUTO strategy as shown below, then, even in that case, EclipseLink may pick TABLE strategy for ID generation.
#GeneratedValue(strategy=GenerationType.AUTO)
Using a Default Generation Strategy
Specifying a strategy of AUTO
allows EclipseLink to select the strategy to use. Typically,
EclipseLink picks TABLE as the strategy, since it is the most portable
strategy. However, when AUTO is specified, schema generation must be
used at least once in order for the default table to be created in the
database.
More details here at PrimaryKey and GeneratedValue Documentation
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;
I am having a problem that hibernate tries to drop foreign keys that dont exist instead of the one that exists. My scenario looks like this.
I want to run a junit tests, before ever test I want to create DB and after ever test I want to drop it. For that I use hibernate create-drop property. However the tricky part is that I want to create my own tables as a way to test newly added sql and verify that it will run fine once I deploy it to the production db server. So what happens is this
Hibernate creates tables automatically
Hibernate creates foreign key relationships
Hibernate runs my drop table scripts (that succeeded since there is no data so no foreign key rule has been broken)
Hibernate runs my create table scripts
Hibernate runs my add foreign constraint scripts
Hibernate runs my insert data scripts
Test is executed
Hibernate tries to remove the foreign key and it fails.
The reason hibernate has not be able to remove it is cause it tried to remove that one that hibernate created and not the one that was created by my scripts.
Any idea how to force hibernate to find out the actual foreign key? Any way to get around this problem?
Thanks everyone
Class for which hibernate creates the table
TodoGroup.java
#Entity
#Table(name = "ToDoGroups")
public class ToDoGroup implements Serializable{
#Id
#GeneratedValue
private Long id;
#Column(name = "Name", length = 50)
private String name;
#ManyToOne
#JoinColumn(name = "UserSettingsId")
#XmlTransient
private UserSettings userSettings;
#OneToMany(mappedBy = "group", cascade = CascadeType.ALL)
private List<ToDoItem> items;
hibernate adding the constraint
alter table ToDoGroups
add constraint FK790BA1FAFE315596
foreign key (UserSettingsId)
references UserSettings
running my own tables that work fine since there is no data so I can remove what hibernate created in order to verify my sql
DROP TABLE IF EXISTS ToDoGroups;
CREATE TABLE ToDoGroups (ID BIGINT NOT NULL IDENTITY, Name VARCHAR(50) NOT NULL, UserSettingsId BIGINT NOT NULL, PRIMARY KEY (ID));
ALTER TABLE ToDoGroups ADD FOREIGN KEY (UserSettingsID) REFERENCES UserSettings (ID);
drop fk it tries to execute
alter table ToDoGroups drop constraint FK790BA1FAFE315596
java.sql.SQLException: Constraint not found FK790BA1FAFE315596 in table: TODOGROUPS in statement [alter table ToDoGroups drop constraint FK790BA1FAFE315596]
tries to remove the table which fails due to the constrain that I have set in my create.sql script
drop table ToDoGroups if exists
java.sql.SQLException: Table is referenced by a constraint in table SYS_REF_SYS_FK_808_810 table: TODOITEMS in statement [drop table ToDoGroups if exists]
Update
I have also noticed that hibernate when it first starts before it creates the tables (so this is way before my scripts are run), tries to remove foreign key in order to drop any table that exists.
So how does hibernate know what foreign key to use? It uses the same key that
first statement it executes
alter table ToDoGroups drop constraint FK790BA1FAFE315596
then it drops all of the tables
drop table ToDoGroups if exists
then it creates table
create table ToDoGroups (
id bigint generated by default as identity (start with 1),
Name varchar(50),
UserSettingsId bigint,
primary key (id)
)
then it adds the same FK
alter table ToDoGroups
add constraint FK790BA1FAFE315596
foreign key (UserSettingsId)
references UserSettings
I think my question here is how does hibernate know what FK to use. It used the same FK in the first drop statement when there was even no table. Later it used that some FK to create the relationship. Shouldn't hibernate first check if the table exists and then tries to determine what is the FK?
As far as I understand, your problem is that your own script and hibernate don't use the same constraint name.
You can specify a constraint name used by hibernate with this annotation on your relationship:
#ForeignKey(name = "fk_UserSettings")
And additionally, in your create.sql:
ALTER TABLE ToDoGroups ADD CONSTRAINT fk_UserSettings FOREIGN KEY (UserSettingsID) REFERENCES UserSettings (ID);
I think my question here is how does hibernate know what FK to use. It used the same FK in the first drop statement when there was even no table. Later it used that some FK to create the relationship. Shouldn't hibernate first check if the table exists and then tries to determine what is the FK?
The foreign key name used by hibernate is the concatenation of
"FK_" + hashcode of referenced entity name + hash code of referenced columns name on that entity.
So it is not a randomly generated key (you will see that it will change if you change your entity name). And that's how hibernate knows the name of the fk to drop (hibernate is expecting that the constraint was created by hibernate with this well known naming strategy).
Hibernate use the name of the constraint to manipulate it. It don't compare the "rule" coded in constraints associated with a table to see if the constraint is already there or not.