Невозможно создать отношение «многие к одному» с каскадом «все удалить». MySQL сообщает, что ограничение внешнего ключа не выполняется при удалении родительского - PullRequest
0 голосов
/ 26 июля 2010

Я недавно начал использовать Hibernate, и я все еще новичок, однако ошибка, с которой я сталкиваюсь, не кажется простой.

Моя текущая среда:

  • Windows 7
  • MySQL 5.1.49-community
  • mysql-connector-java-5.1.13-bin.jar
  • зимуют-распределение-3.6.0.Beta1

Я следую книге «Гибернация в действии» и все сделал так, как она предлагает.

Когда я пытаюсь удалить родительский объект (UserClass) отношения «многие к одному». Я ожидал, что родительский объект был удален и все его дочерние (пользователь) тоже. Тем не менее, я получил java.sql.BatchUpdateException, например:

Exception in thread "main" org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1215)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:382)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
        at netbeansproject.Main.testUserClassAndUsers(Main.java:42)
        at netbeansproject.Main.main(Main.java:55)
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`lojatest`.`user`, CONSTRAINT `fk_User_UserClass1` FOREIGN KEY (`user_class_id`) REFERENCES `userclass` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
        at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020)
        at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1451)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
        ... 9 more

Похоже, что это связано с константами внешнего ключа MySQL, особенно в отношении «УДАЛИТЬ НЕТ ДЕЙСТВИЯ, ОБНОВЛЕНИЕ НЕТ ДЕЙСТВИЯ», ​​однако я не совсем эксперт MySQL.

Я нашел несколько других вопросов о подобной ситуации, и я все еще не мог найти решение для этого. Кто-нибудь может мне помочь?

Большое спасибо.

Вот соответствующий код:

User.java:

package domain;

public class User {

    private String userName;
    private String password;
    private Boolean blocked;
    private UserClass userClass;

    public User() {
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Boolean getBlocked() {
        return blocked;
    }

    public void setBlocked(Boolean blocked) {
        this.blocked = blocked;
    }

    public UserClass getUserClass() {
        return this.userClass;
    }

    public void setUserClass(UserClass userClass) {
        this.userClass = userClass;
    }
}

User.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="domain">
    <class name="User" table="user">
        <id
            column="username"
            name="userName"
            type="string">
            <generator class="assigned"/>
        </id>
        <property
            column="password"
            name="password"
            not-null="true"
            type="string"/>
        <property column="blocked" name="blocked" type="boolean"/>
        <many-to-one
            name="userClass"
            column="user_class_id"
            class="UserClass"
            not-null="true"/>
    </class>
</hibernate-mapping>

UserClass.java

package domain;

import java.util.HashSet;
import java.util.Set;

public class UserClass {

    private Long id;
    private String title;
    private String permissions;
    private Set users = new HashSet();

    public UserClass() {
    }

    public Long getId() {
        return id;
    }

    private void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getPermissions() {
        return permissions;
    }

    public void setPermissions(String permissions) {
        this.permissions = permissions;
    }

    public void setUsers(Set users) {
        this.users = users;
    }

    public Set getUsers() {
        return this.users;
    }

    public void addUser(User user) {
        user.setUserClass(this);
        this.users.add(user);
    }
}

UserClass.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="domain">
    <class
        name="UserClass"
        table="userclass">
        <id
            column="id"
            name="id">
            <generator class="native"/>
        </id>
        <property
            column="title"
            name="title"
            not-null="true"
            type="string"/>
        <property
            column="permissions"
            name="permissions"
            not-null="true"
            type="string"/>
        <set
            name="users"
            inverse="true"
            cascade="all-delete-orphan">
            <key column="user_class_id"/>
            <one-to-many class="User"/>
        </set>
    </class>
</hibernate-mapping>

DatabaseFactory.java:

package Database;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class DatabaseFactory {

    private static DatabaseFactory instance = null;

    private SessionFactory sessionFactory;

    public static DatabaseFactory getInstance() {
        if (DatabaseFactory.instance == null) {
            DatabaseFactory.instance = new DatabaseFactory().init();
        }

        return DatabaseFactory.instance;
    }

    public SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }

    public Session getSession() {
        return this.sessionFactory.openSession();
    }

    private DatabaseFactory init() {
        Configuration cfg = new Configuration();

        cfg.addClass(domain.UserClass.class);
        cfg.addClass(domain.User.class);

        cfg.setProperties(System.getProperties());
        cfg.configure();
        SessionFactory sessions = cfg.buildSessionFactory();

        sessionFactory = cfg.configure().buildSessionFactory();
        return this;
    }
}

Main.java (тестовый класс):

package netbeansproject;

import Database.DatabaseFactory;
import domain.*;

import java.util.List;
import java.util.Iterator;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class Main {
    public void testUserClassAndUsers() {
        System.out.println("Testing Users and UserClasses...");

        Session newSession = DatabaseFactory.getInstance().getSession();

        System.out.println("1 - Creating UserClasses:");
        Transaction t1 = newSession.beginTransaction();
        UserClass uc1 = new UserClass();
        uc1.setTitle("UserClass 1");
        uc1.setPermissions("XYZ");
        newSession.save(uc1);
        t1.commit();

        System.out.println("2 - Creating Users:");
        Transaction t2 = newSession.beginTransaction();
        User u1 = new User();
        u1.setUserName("User 1");
        u1.setPassword("Password 1");
        u1.setBlocked(false);
        u1.setUserClass(uc1);
        newSession.save(u1);

        User u2 = new User();
        u2.setUserName("User 2");
        u2.setPassword("Password 2");
        u2.setBlocked(false);
        u2.setUserClass(uc1);
        newSession.save(u2);
        t2.commit();

        System.out.println("3 - Deleting UserClass (\"UserClass 1\"):");
        Transaction t3 = newSession.beginTransaction();
        newSession.delete(uc1);
        t3.commit();

        newSession.close();
    }

    public static void main(String[] args) {
        Main instance = new Main();

        instance.testUserClassAndUsers();
    }
}

SQL-скрипт для создания БД (сгенерированный MySQL Workbench):

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

DROP SCHEMA IF EXISTS `LojaTest` ;
CREATE SCHEMA IF NOT EXISTS `LojaTest` ;
SHOW WARNINGS;
USE `LojaTest` ;

-- -----------------------------------------------------
-- Table `LojaTest`.`UserClass`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `LojaTest`.`UserClass` ;

SHOW WARNINGS;
CREATE  TABLE IF NOT EXISTS `LojaTest`.`UserClass` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
  `title` VARCHAR(45) NOT NULL ,
  `permissions` VARCHAR(16) NULL ,
  PRIMARY KEY (`id`) ,
  UNIQUE INDEX `id_UNIQUE` (`id` ASC) )
ENGINE = InnoDB;

SHOW WARNINGS;

-- -----------------------------------------------------
-- Table `LojaTest`.`User`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `LojaTest`.`User` ;

SHOW WARNINGS;
CREATE  TABLE IF NOT EXISTS `LojaTest`.`User` (
  `username` VARCHAR(10) NOT NULL ,
  `password` VARCHAR(30) NOT NULL ,
  `blocked` TINYINT(1)  NOT NULL DEFAULT false ,
  `user_class_id` INT UNSIGNED NOT NULL ,
  PRIMARY KEY (`username`) ,
  UNIQUE INDEX `id_UNIQUE` (`username` ASC)
)
ENGINE = InnoDB;

SHOW WARNINGS;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Примечание. Я не создаю никакого внешнего ключа ... однако после запуска моего кода в таблице User создается внешний ключ, ссылающийся на идентификатор таблицы UserClass. До этого теста я пробовал тот же сценарий SQL, но со следующими параметрами для таблицы User:

CONSTRAINT `fk_User_UserClass1`
    FOREIGN KEY (`user_class_id` )
    REFERENCES `LojaTest`.`UserClass` (`id` )
    ON DELETE CASCADE
    ON UPDATE NO ACTION

И

CONSTRAINT `fk_User_UserClass1`
    FOREIGN KEY (`user_class_id` )
    REFERENCES `LojaTest`.`UserClass` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION

Ничего из этого не сработало.

Еще раз спасибо.

1 Ответ

0 голосов
/ 02 августа 2010

Я изменил свой подход и начал использовать аннотации.

Сначала у меня возникла та же проблема, но потом я немного прочитал о EntityManager в JPA и исправил ее.

Проблема была связана с удалением UserClass в том же контексте EntityManager, в котором он был создан.

Я не вернусь к этому основанному на XML подходу к отображению, потому что он не стоит (ИМХО). Тем не менее, я думаю, что это может быть решено с помощью более чем одного сеанса Hibernate. Один для создания объектов, а другой для удаления объекта.

Надеюсь, это может кому-то помочь. Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...