Итак, у меня есть 4 объекта (Person, Car, Garage, Image)
отношение между Person и Car - oneToMany (у одного человека может быть много машин) при использовании 'session.remove (somePerson)' I есть исключение: «Невозможно удалить или обновить родительскую строку: ограничение внешнего ключа не выполнено». Однако я могу использовать 'session.remove (someCar)', и это работает. Я предполагаю, что моя проблема заключается в том, что когда человек удален, Hibernate не может обновить внешний ключ в Cars, и я предполагаю, что это как-то связано с каскадированием.
Просто чтобы уточнить: когда я удаляю (somePerson) желаемый результат is: somePerson было удалено. его автомобили не будут удалены! (будет иметь нулевое значение в столбце владельца).
Автомобиль. java
package com.example;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "cars")
public class Car {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String licensePlate;
private double price;
private int year;
@ManyToOne(fetch = FetchType.LAZY)
@Cascade(CascadeType.SAVE_UPDATE)
@JoinColumn(name = "owner_id")
private Person owner;
@OneToOne(fetch = FetchType.LAZY)
@Cascade(CascadeType.ALL)
private Image image;
@ManyToMany
@Cascade({CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
name = "cars_garages",
joinColumns = @JoinColumn(name = "car_id"),
inverseJoinColumns = @JoinColumn(name = "garage_id")
)
private List<Garage> garageList;
//GROUP C'tors
public Car(String licensePlate, double price, int year) {
this();
this.licensePlate = licensePlate;
this.price = price;
this.year = year;
}
public Car() {
garageList = new ArrayList<>();
}
//GROUP adders
public void addGarage(Garage garage) {
if (!garageList.contains(garage))
garageList.add(garage);
if (!garage.getCarList().contains(this))
garage.getCarList().add(this);
}
//GROUP setters and getters
public int getId() {
return id;
}
public String getLicensePlate() {
return licensePlate;
}
public void setLicensePlate(String licensePlate) {
this.licensePlate = licensePlate;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
if (image.getCar() != this)
image.setCar(this);
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
if (!owner.getCarList().contains(this))
owner.getCarList().add(this);
}
public List<Garage> getGarageList() {
return garageList;
}
public void setGarageList(List<Garage> garageList) {
this.garageList = garageList;
}
@Override
public String toString() {
StringBuilder string = new StringBuilder("Car: ID = " + id + ", license plate = " + licensePlate +
", price = " + price + ", year = " + year + "\nowner details:\n\t" + "ID: " + owner.getId()
+ ", full name = " + owner.getFirstName() + " " + owner.getLastName() + ", email address = " +
owner.getEmailAddress() + ", password = " + owner.getPassword() + "\n"
+ "This car can get service at the following addresses:\n");
for (Garage garage : garageList)
string.append("\t").append(garage.getAddress()).append("\n");
return string.toString();
}
}
Персона. java
package com.example;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "persons")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String firstName, lastName, emailAddress, password;
@OneToMany(
//cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "owner"
)
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DETACH})
private List<Car> carList;
@ManyToMany//(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@Cascade({CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
name = "persons_garages",
joinColumns = @JoinColumn(name = "person_id"),
inverseJoinColumns = @JoinColumn(name = "garage_id")
)
private List<Garage> garageList;
//GROUP C'tors
public Person(String firstName, String lastName, String password, String emailAddress) {
this();
this.firstName = firstName;
this.lastName = lastName;
this.password = password;
this.emailAddress = emailAddress;
}
public Person() {
this.carList = new ArrayList<>();
this.garageList = new ArrayList<>();
}
//GROUP adders
public void addCar(Car car) {
if (!carList.contains(car))
{
carList.add(car);
car.setOwner(this);
}
}
public void addGarage(Garage garage) {
if (!garageList.contains(garage))
garageList.add(garage);
if (!garage.getOwners().contains(this))
garage.getOwners().add(this);
}
public void removeCar(Car car) {
carList.remove(car);
}
//GROUP setters and getters
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public List<Car> getCarList() {
return carList;
}
public void setCarList(List<Car> carList) {
this.carList = carList;
}
public List<Garage> getGarageList() {
return garageList;
}
public void setGarageList(List<Garage> garageList) {
this.garageList = garageList;
}
}
Приложение. java
package com.example;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.Parent;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class App {
private static final int NUM_OF_PERSONS = 5;
private static final int NUM_OF_CARS = 5;
private static final int NUM_OF_GARAGES = 2;
private static final int NUM_OF_IMAGES = 5;
private static Session session;
public static void main(String[] args) {
try
{
SessionFactory sessionFactory = getSessionFactory();
session = sessionFactory.openSession();
session.beginTransaction();
generateCars();
generatePersons();
generateGarages();
generateImages();
connectEntities();
session.clear();
List<Person> personList = getAllOfType(Person.class);
session.remove(personList.get(0));
session.flush(); // Exception is being thrown here
session.getTransaction().commit();
printAllOfType(Garage.class);
printAllOfType(Car.class);
}
catch (Exception exception)
{
if (session != null)
session.getTransaction().rollback();
System.err.println("An error occurred, changes have been rolled back.");
exception.printStackTrace();
} finally
{
assert session != null;
session.close();
session.getSessionFactory().close();
}
}
private static SessionFactory getSessionFactory() throws HibernateException {
java.util.logging.Logger.getLogger("org.hibernate").setLevel(Level.OFF);
Configuration configuration = new Configuration();
configuration.addAnnotatedClass(Car.class);
configuration.addAnnotatedClass(Person.class);
configuration.addAnnotatedClass(Garage.class);
configuration.addAnnotatedClass(Image.class);
ServiceRegistry serviceRegistry =
new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
return configuration.buildSessionFactory(serviceRegistry);
}
private static void generateCars() {
Random random = new Random();
for (int i = 0; i < NUM_OF_CARS; i++)
{
Car car = new Car("MOO-" + random.nextInt(999999), 100000,
2000 + random.nextInt(19));
session.save(car);
}
session.flush();
}
private static void generatePersons() {
Random random = new Random();
String[] firstNames = {"Avi", "Dan", "John", "Didi", "Avihu"};
String[] lastNames = {"Hemmo", "Bilzerian", "Snow", "Harrari", "Medina"};
for (int i = 0; i < NUM_OF_PERSONS; i++)
{
Person person = new Person(firstNames[i % firstNames.length], lastNames[i % lastNames.length],
String.valueOf(random.nextInt(99999)),
firstNames[i % firstNames.length] + lastNames[i % lastNames.length] + "@fake.com");
session.save(person);
}
session.flush();
}
private static void generateGarages() {
String[] addresses = {"1 1st st, New York, NY", "5 5th st, New York, NY"};
for (int i = 0; i < NUM_OF_GARAGES; i++)
{
Garage garage = new Garage(addresses[i % addresses.length]);
session.save(garage);
}
session.flush();
}
private static void generateImages() {
for (int i = 0; i < NUM_OF_IMAGES; i++)
session.save(new Image());
session.flush();
}
private static <T> List<T> getAllOfType(Class<T> objectType) {
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> query = builder.createQuery(objectType);
query.from(objectType);
return session.createQuery(query).getResultList();
}
private static <T> void printAllOfType(Class<T> objectType) {
List<T> tList = getAllOfType(objectType);
for (T object : tList)
System.out.println(object);
}
private static void connectEntities() {
List<Person> persons = getAllOfType(Person.class);
List<Car> cars = getAllOfType(Car.class);
List<Garage> garages = getAllOfType(Garage.class);
List<Image> images = getAllOfType(Image.class);
// connect cars with owners & cars with garages
for (int i = 0; i < cars.size(); i++)
{
cars.get(i).setOwner(persons.get(i % persons.size()));
cars.get(i).addGarage(garages.get(i % garages.size()));
cars.get(i).setImage(images.get(i % images.size()));
session.update(cars.get(i));
}
session.flush();
// connect persons with garages
for (int i = 0; i < persons.size(); i++)
{
persons.get(i).addGarage(garages.get(i % garages.size()));
session.update(persons.get(i));
}
session.flush();
}
}
Журнал ошибок
An error occurred, changes have been rolled back.
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1356)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1339)
at com.example.App.main(App.java:42)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3551)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3810)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:124)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:723)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1352)
... 2 more
Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`lab5`.`cars`, CONSTRAINT `FK82ccqb3p17md157c33e2qerq9` FOREIGN KEY (`owner_id`) REFERENCES `persons` (`id`))
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 14 more