I am working with intelij, java, spring and hiberante to create tables in my mysql database. My code executes without a problem but for some reason hibernate creates a table I deleted. The table connected two entities with many to many relation with a composite key. One entity was deleted and so the composite key table was also deleted because it was no longer needed. I updated the other table so there is no leftover connections. I tried changing hibernates ddl-auto from update to create. It drops all and creates all with that table that doesn't exist. I also droped the whole schema in mysql workbench multiple times. I am assuming there is some leftover data somewhere in hibernate but I cannot find it especially since the same code works on another computer where it doesn't create the deleted table.
Tis is the hibernate part from my application properties:
# Hibernate properties
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.hibernate.ddl-auto=create
Below is the entity that I didn't delete that was connected to the projection_seat_list which doesn't exist anymore as well as the seat entity:
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "projections")
public class Projection {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int projectionId;
#Column(name = "date")
private String date;
#Column(name = "startTime")
private String startTime;
#ManyToOne
#JoinColumn(name = "idHall")
private Hall hall;
#ManyToOne
#JoinColumn(name = "idMovie")
private Movie movie;
#Column(name = "seatList")
#ElementCollection
private List<Integer> seatList;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "projection", cascade = CascadeType.ALL)
private List<Ticket> ticketList;
}
This is the part of the output code regarding the problem when app is executed:
Hibernate: drop table if exists `projection_seat_list`
Hibernate: drop table if exists `projections`
Hibernate: create table `projection_seat_list` (`projection_id` integer not null, `seat_list` integer) engine=MyISAM
Hibernate: create table `projections` (`id` integer not null, `date` varchar(255), `start_time` varchar(255), `id_hall` integer, `id_movie` integer, primary key (`id`)) engine=MyISAM
Hibernate: alter table `projection_seat_list` add constraint `FK8rkfyw0lua4jjaamrw3kl3llo` foreign key (`projection_id`) references `projections` (`id`)
Here is my whole code on github if you'd like to see the structure:
https://github.com/denibakulic/Java.git
It was my mistake because I had a list in my projection model and with that automatically another table is created because you can't have a list. I got confused because the name of the created table of the same of the one that I previously deleted.
Related
UPDATE: Changed code to be coherent to db model and changed details of the model itself. Also added code of the section that causes the error.
I am trying to implement a small database consulting system in Hibernate with PostgreSQL and having issues with one specific pair of tables. As you can see, it's a system for car rental services, and the tables store drivers and rentals. A driver is supposed to be able to have multiple rentals (but not the other way around).
Problem Tables
CREATE TABLE Driver(
cod_driver SERIAL PRIMARY KEY,
cod_client INTEGER,
num_license BIGINT UNIQUE,
expiration_license DATE,
ident_driver BIGINT,
FOREIGN KEY (cod_client)
REFERENCES Client(cod_client)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE Rental(
cod_rental SERIAL PRIMARY KEY,
cod_plate VARCHAR(10),
cod_dest VARCHAR(10),
cod_driver INTEGER,
date_delivery DATE,
FOREIGN KEY (cod_plate)
REFERENCES Vehicle(cod_plate)
ON UPDATE CASCADE
ON DELETE NO ACTION,
FOREIGN KEY (cod_dest)
REFERENCES Location(cod_location)
ON UPDATE CASCADE
ON DELETE NO ACTION,
FOREIGN KEY (cod_driver)
REFERENCES Driver(cod_driver)
ON UPDATE CASCADE
ON DELETE CASCADE
);
I did my implementation using Hibernate as follows (short of getters/setters for brevity):
Driver
#Entity
public class Driver {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer cod_driver;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cod_client")
private Client client;
private Long num_license;
private Long ident_driver;
private LocalDate expiration_license;
}
Rental
#Entity
public class Rental {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer cod_rental;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cod_plate")
private Vehicle vehicle;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cod_dest")
private Location location_dest;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cod_driver")
private Driver driver;
private LocalDate date_delivery;
Context of PSQLException
Persist function call in Main.java (clientGet is obtained through successfull queries, and inserts is just a class for queries):
Driver d = new Driver(clientGet, 3294324792L, 321312931L, LocalDate.of(2030, 10, 01));
inserts.insertEntity(d);
insertEntity function:
public void insertEntity(Object o) // Basic insertion of any persistent object
{
em.getTransaction().begin();
em.persist(o);
em.getTransaction().commit();
}
Error
The error I get is this:
Caused by: org.postgresql.util.PSQLException:
ERROR: insert or update on table "driver" violates foreign key
constraint "fkdfq0qhvpkw1dqguk6dv1dsj0t"
Detail: Key (cod_driver)=(3) is not present in table "rental".
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2497)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2233)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:310)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:446)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:370)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:149)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:124)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
What I've Considered
From my understanding, the relationship didn't need to be bidirectional (though I did try to use mappedBy), given that I don't store rentals in driver table.
I just don't understand what constraint could possibly be violated by this. It's as if it expects the value of cod_driver to be already in the rentals table, but a rental entity depends on the pre-existence of the driver existence. SQL for the database doesn't seem to have any constraint like that.
Can someone help me understand what I'm doing wrong? I tried all things I found, but nothing shed any light on this.
use many to many relationship between rental and driver.the same problem i faced once in my PurchaseOrder and PaymentMethods relationship.
#ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
#JoinTable(name = "rental_driver", joinColumns = #JoinColumn(name = "rental_id"), inverseJoinColumns = #JoinColumn(name = "driver_id"))
private List driver = new List();
I have this Parent class
#Entity
#Table(name = "category")
#NamedQuery(name = "category.findAll", query = "SELECT c FROM Category c")
public class Category implements Serializable {
public Category(){}
#Column(name = "name", nullable = false)
#Id
private String name;
#Column(name = "col2")
private Boolean col2;
}
And i have referenced the parent table in child table as follows:
#ManyToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "cat_name")
private Category category
when i run this JPQL query
update Category c SET c.name=:newName ,c.termsCanHaveChildren=:canHaveChdrn where c.name=:oldName
it's return with foreign key constraint error while i have put Cascade All in child field
Cannot delete or update a parent row: a foreign key constraint fails (`terms`.`term`, CONSTRAINT `FKaykenypxci167nqioh4xx9p3a` FOREIGN KEY (`cat_name`) REFERENCES `category` (`name`))
The problem lays at the constraint being generated by your persistence provider (hibernate), for the #JoinColumn(name = "cat_name") at the child table (and not with the CascadeType that you're defining)...
The generated constraint should indicated that when the PK of Category is Updated, any reference to such column should be updated also...
I believe this configuration should work (but you need to test it first, because I always generated my database model using scripts and not using hibernate features):
#ManyToOne
#JoinColumn(
name = "cat_name",
foreignKey = #ForeingKey(
name = "fk_child_category",
foreignKeyDefinition = "FOREIGN KEY (cat_name) REFERENCES category ON UPDATE CASCADE"
)
)
private Category category;
Also you need to check if your database supports "ON UPDATE CASCADE"... According to this link, oracle does not... (What database are you using?)
If this does not work, try the suggestion of Michelle...
That's expected: you are changing the Primary Key (#Id), that's used in a Foreign Key (#JoinColumn).
Use a surrogated immutable primary key.
I'm relatively new to JPA and Hibernate and am trying to see how the #OneTo One annotation works, let's say I have an entity "Task" with the following relation:
#OneToOne
#JoinColumn(name = "manager_id")
private Manager manager;
And there's the entity "Manager":
#Entity
#Table(name = "manager")
public class Manager {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String name;
public Manager() {
}
When I run the test file along with the "hibernate.hbm2ddl.auto" set to "update" I get a Many to One relation in the database (as you can see, there is no unique constraint of any kind that'd make it a one to one relation):
CREATE TABLE IF NOT EXISTS `timesheet`.`task` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`completed` BIT(1) NOT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
`manager_id` BIGINT(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `FK3635851B178516` (`manager_id` ASC),
CONSTRAINT `FK3635851B178516`
FOREIGN KEY (`manager_id`)
REFERENCES `timesheet`.`manager` (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
To be sure of this I tried adding two records with the same manager id and were indeed added, I also tried setting the unique constraint like "#Table(name = "Task",uniqueConstraints = #UniqueConstraint(columnNames =..." but no luck.
So Why is this happening and what's exactly the pros of using #OneToOne annotaion if no application logic is applied to validate this?
Also, Is there any chance that Hibernate is not able to do the DDL generation properly?
(I know that generation of schemas through hibernate is only meant for testing)
In a unidirectional relationship you will get the expected unique constraint if you mark it as "optional=false". You also get it if you set the join column explicitly as unique, of course.
So either
#OneToOne(optional=false)
#JoinColumn(name = "manager_id")
private Manager manager;
or
#OneToOne
#JoinColumn(name = "manager_id", unique=true)
private Manager manager;
So why do you need to mark it as not optional?
My guess is that, when a value is optional, the column can contain many null values, but in many databases this can not be done when a unique constraint is present. You can do it in MySQL though, so maybe the Hibernate generator is not taking the database into account in this case (a bug?).
See a discussion about MySQL handling of nulls here.
I had this issue too and I just needed to add the referenced column so I can get a generated table:
#Entity(name = "news")
public class News extends BaseEntity {
#Column(length = 500)
private String title;
#Column(length = 2000)
private String description;
#OneToOne(optional = false, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "file_id", referencedColumnName = "id", unique = true)
private Picture picture;
}
This is my entity class:
#Entity
#Table(name="APPEAL")
public class Appeal
{
#Id
#Column(name="ID_APPEAL")
#GeneratedValue(strategy = GenerationType.AUTO ,generator="SQ_APPEAL")
#SequenceGenerator(name="SQ_APPEAL", sequenceName="SQ_APPEAL")
private Long idAppeal;
#ManyToOne
#JoinColumn(name="ID_USER")
#OnDelete(action = OnDeleteAction.CASCADE)
private User user;
#ManyToOne
#JoinColumn(name="ID_APPEAL_PARENT")
#OnDelete(action = OnDeleteAction.CASCADE)
private Appeal parent;
...
Now, to generate the SQL to create my tables I'm using this code:
for (#SuppressWarnings("rawtypes") final Class entity : classes) {
ejb3Configuration.addAnnotatedClass(entity);
}
dialectProps = new Properties();
dialectProps.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
hibernateConfiguration = ejb3Configuration.getHibernateConfiguration();
final StringBuilder script = new StringBuilder();
final String[] creationScript = hibernateConfiguration.generateSchemaCreationScript(Dialect
.getDialect(dialectProps));
But hibernate is not getting the cascade for the self reference:
create table APPEAL (ID_APPEAL bigint not null auto_increment, ID_USER bigint, ID_APPEAL_PARENT bigint, primary key (ID_APPEAL)) ENGINE=InnoDB;
alter table APPEAL add index FK_kcwnikcyoq8pskhdhnmtc0h9f (ID_USER), add constraint FK_kcwnikcyoq8pskhdhnmtc0h9f foreign key (ID_USER) references USER (ID_USER) on delete cascade;
alter table APPEAL add index FK_5ay1y0vn1nyeb9vgkpdb98q18 (ID_APPEAL_PARENT), add constraint FK_5ay1y0vn1nyeb9vgkpdb98q18 foreign key (ID_APPEAL_PARENT) references APPEAL (ID_APPEAL);
How should I define the cascade for the self referencing column?
Thanks
MySQL does not support it.
Deviation from SQL standards: If ON UPDATE CASCADE or ON UPDATE SET NULL recurses to update the same table it has previously updated during the cascade, it acts like RESTRICT. This means that you cannot use self-referential ON UPDATE CASCADE or ON UPDATE SET NULL operations.
I have a problem very similar to this: How do I join tables on non-primary key columns in secondary tables?
But I'm not sure if I can apply the same solution.
I have two tables like these:
CREATE TABLE CUSTOMER
(
CUSTOMER_ID INTEGER NOT NULL,
DETAIL_ID INTEGER NOT NULL,
PRIMARY KEY( CUSTOMER_ID ),
CONSTRAINT cust_fk FOREIGN KEY( DETAIL_ID ) REFERENCES DETAILS( DETAIL_ID )
)
CREATE TABLE DETAILS
(
DETAIL_ID INTEGER NOT NULL,
OTHER INTEGER NOT NULL,
PRIMARY KEY( DETAIL_ID )
)
I'd like to map these tables to a single class called Customer, so I have:
#Entity
#Table(name = "CUSTOMERS")
#SecondaryTable(name = "DETAILS", pkJoinColumns=#PrimaryKeyJoinColumn(name="DETAIL_ID"))
public class Customer {
#Id
#GeneratedValue
#Column(name = "CUSTOMER_ID")
private Integer id;
#Column(table = "DETAILS", name = "OTHER")
private Integer notes;
// ...
}
but this works only if DETAIL_ID matches CUSTOMER_ID in the primary table.
So my question is: how can i use a foreign-key field in my primary table to join on the primary-key of the secondary table?
UPDATE
I tried to set:
#SecondaryTable(name = "DETAILS", pkJoinColumns=#PrimaryKeyJoinColumn(name="DETAIL_ID", referencedColumnName="DETAIL_ID"))
but when I run the application I get this exception:
org.hibernate.MappingException: Unable to find column with logical name: DETAIL_ID in org.hibernate.mapping.Table(CUSTOMERS) and its related supertables and secondary tables
For anyone looking for an answer to this, using #SecondaryTable is not the way to join two tables with non-primary key columns, because Hibernate will try to assosiate the two tables by their primary keys by default; you have to use #OneToMany review http://viralpatel.net/blogs/hibernate-one-to-many-annotation-tutorial/ for a solution, here's a code snippet in case that url stops working:
Customer Class:
#Entity
#Table(name="CUSTOMERS")
public class Customer {
#Id
#GeneratedValue
#Column(name="CUSTOMER_ID")
private Integer id;
#ManyToOne
#JoinColumn(name="DETAIL_ID")
private Details details;
// Getter and Setter methods...
}
Details Class:
#Entity
#Table(name="DETAILS")
public class Details {
#Id
#GeneratedValue
#Column(name="DETAIL_ID")
private int detailId;
#Column(name="OTHER")
private String other;
#OneToMany(mappedBy="details")
private Set<Customer> customers;
// Getter and Setter methods...
}
This is easily accessible through hibernate with the following code:
Session session = HibernateUtil.getSessionFactory().openSession();
Query query = session.createQuery("select id, details.other from Customer");
I hope this helps anyone out there spending hours searching for a way to achieve this like I did.
You can use the referenceColumnName attribute of the #PrimaryKeyJoinColumn annotation to define the join column to the referenced table. In fact, by combining use of name/referencedColumnName you can join on arbitrary on both sides, with the constraint that if duplicates are found your ORM provider will throw an exception.