简体   繁体   中英

Hibernate and Spring Data with Spring DBUnit on HSQLDB - Unable to delete due to foreign key constraint

I'm using Hibernate and Spring Data to model a very simple domain:

@Entity
public class User implements Serializable {

    private static final long serialVersionUID = -5501812656863255674L;

    @Id
    private String emailAddress;

    @Column
    private String forename;

    @Column
    private String surname;

    @Column
    @Enumerated(EnumType.STRING)
    private UserRole role;

    @OneToMany(cascade = { CascadeType.ALL })
    private List<Team> teams;
}

and

@Entity
public class Team implements Serializable {

    private static final long serialVersionUID = -3734641391628154428L;

    private static final BigDecimal STARTING_BUDGET = new BigDecimal(100);

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(unique = true)
    private String name;
}

I then have an 'updateUser' method in a data service which does as it is named. The idea is that to add a Team to a User, this method would be used and the cascading would result in the Team being persisted in the database.

@Override
    public void updateUser(final User user) throws IntegrationException {

        if (userRepository.exists(user.getEmailAddress())) {
            userRepository.save(user);
        } else {
            throw new IntegrationException(IntegrationExceptionCode.USER_NOT_FOUND);
        }
    }

I'm then unit testing this method using a HSQLDB database and Spring DBUnit to setup the initial database contents and the expected DB contents:

Initial DB Content Config

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <User emailAddress="user1@test.com" forename="User" surname="One" role="MANAGER" />
    <Player />
    <User_Team />
    <Team />
</dataset>

Expected DB Content Config

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <User emailAddress="user1@test.com" forename="User" surname="One" role="MANAGER" />
    <Player />
    <Team id="1" name="Test Team" totalScore="0" status="INCOMPLETE" remainingBudget="100" />
    <User_Team User_emailAddress="user1@test.com" Teams_id="1" />
</dataset>

I then have two tests: one which tests the update success; one which tests that a user which is not already in the system can't be updated.

Success Test

@Test
@ExpectedDatabase("UserData-WithTeam.xml")
public void testUpdateUser_AddedTeam_Success() throws Exception {
    // arrange
    final User user = UserTestDataBuilder.aManager(VALID_EMAIL_ADDRESS, "User", "One").withTeam().build();

    // act
    userDataService.updateUser(user);

    // assert - done by @ExpectedDatabase annotation
}

'User Does Not Exist' Test

@Test
    public void testUpdateUser_AddedTeam_UserDoesNotExist() throws Exception {
        // arrange
        thrownException.expect(IntegrationException.class);
        thrownException.expect(CustomIntegrationExceptionMatcher.hasCode(IntegrationExceptionCode.USER_NOT_FOUND));

        final User user = UserTestDataBuilder.aManagerWithEmailAddress(INVALID_EMAIL_ADDRESS).withTeam().build();

        // act
        userDataService.updateUser(user);

        // assert
        Assert.fail("Exception expected");
    }

The 'success' test works fine. However, the 'failure case' test errors with the following error:

java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no action; FK_RVG5KHM9RO439HI17HPAUV5KG table: USER_TEAM
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.execute(Unknown Source)
    at org.dbunit.database.statement.SimpleStatement.executeBatch(SimpleStatement.java:69)
    at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:126)
    at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
    at com.github.springtestdbunit.DbUnitRunner.setupOrTeardown(DbUnitRunner.java:194)
    at com.github.springtestdbunit.DbUnitRunner.beforeTestMethod(DbUnitRunner.java:66)
    at com.github.springtestdbunit.DbUnitTestExecutionListener.beforeTestMethod(DbUnitTestExecutionListener.java:186)
    at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:249)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hsqldb.HsqlException: integrity constraint violation: foreign key no action; FK_RVG5KHM9RO439HI17HPAUV5KG table: USER_TEAM
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.StatementDML.performReferentialActions(Unknown Source)
    at org.hsqldb.StatementDML.delete(Unknown Source)
    at org.hsqldb.StatementDML.executeDeleteStatement(Unknown Source)
    at org.hsqldb.StatementDML.getResult(Unknown Source)
    at org.hsqldb.StatementDMQL.execute(Unknown Source)
    at org.hsqldb.Session.executeCompiledStatement(Unknown Source)
    at org.hsqldb.Session.executeDirectStatement(Unknown Source)
    at org.hsqldb.Session.execute(Unknown Source)
    ... 32 more

It seems to be suggesting that it can't tear down the test data added in the 'success' test (and I've added the @Ignore annotation to the success test and the failure test passes). My question is why? My cascade on the @OneToMany relationship is set to ALL so all entities saved as part of the User-Team relationship should be removed.

Does anyone have any ideas?

我认为您在USER_TEAM表中有一个Integrity约束: UPDATE NO ACTION这就是为什么给java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no action;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM