Prevent Table Sorting Before Execution in Order to Insert Into Circular Dependency

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Prevent Table Sorting Before Execution in Order to Insert Into Circular Dependency

leojhartiv
This post was updated on .

I wanted to resurrect a topic I posted a while back, but with a more focused discussion.
I have this circular reference:

Using DBUnit 2.3, we would resolve importing data into these tables by using a refresh operation with XML like this:

	<ACCOUNT_MANAGER ID="100" MANAGER_CODE="100" PARTY_ID="1000" VERSION="0" PRIMARY_ACCOUNT_ID="[NULL]" />
	
	<ACCOUNT ID="1011"  ACCOUNT_TYPE="INDVDL" ACCOUNT_STATUS="OPEN" ACCOUNT_CODE="AC10001" NAME="FakeName-Individual" OWNER_PARTY_ID="1000" VERSION="0" ACCOUNT_MANAGER_ID="100" />
	
	<ACCOUNT_MANAGER ID="100" MANAGER_CODE="100" PARTY_ID="1000" VERSION="0" PRIMARY_ACCOUNT_ID="1011" />

DBUnit would then do the following:

  1. Insert ACCOUNT_MANAGER 100 with null PRIMARY_ACCOUNT_ID
  2. Insert ACCOUNT 1011 with ACCOUNT_MANAGER_ID 100
  3. Update ACCOUNT_MANAGER 100, setting PRIMARY_ACCOUNT_ID to 1011
This pattern is described at the bottom of this article.

Ever since we upgraded to DBUnit 2.47 (driven by upgrading to Spring 3.0), the above no longer works. It seems that now DBUnit first sorts all table elements by table name and then executes the SQL. So using the example above, we get:

1306951950014|0|1|statement|update PUBLIC.ACCOUNT_MANAGER set MANAGER_CODE = ?, PARTY_ID = ?, VERSION = ?, PRIMARY_ACCOUNT_ID = ? where ID = ?|update PUBLIC.ACCOUNT_MANAGER set MANAGER_CODE = '100', PARTY_ID = '1000', VERSION = 0, PRIMARY_ACCOUNT_ID = '' where ID = '100'
1306951950014|0|1|statement|insert into PUBLIC.ACCOUNT_MANAGER (ID, MANAGER_CODE, PARTY_ID, VERSION, PRIMARY_ACCOUNT_ID) values (?, ?, ?, ?, ?)|insert into PUBLIC.ACCOUNT_MANAGER (ID, MANAGER_CODE, PARTY_ID, VERSION, PRIMARY_ACCOUNT_ID) values ('100', '100', '1000', 0, '')
1306951950014|0|1|statement|update PUBLIC.ACCOUNT_MANAGER set MANAGER_CODE = ?, PARTY_ID = ?, VERSION = ?, PRIMARY_ACCOUNT_ID = ? where ID = ?|update PUBLIC.ACCOUNT_MANAGER set MANAGER_CODE = '100', PARTY_ID = '1000', VERSION = 0, PRIMARY_ACCOUNT_ID = '1011' where ID = '100'
ERROR [01/06/2011 14:12:30.014]              BaseDataInitializer[  32] - An unexpected error occurred while initializing data: 
com.fidelity.shares.util.datainit.DataInitializerException: An error occurred while initializing data: 
	at com.fidelity.shares.util.datainit.dbunit.DbUnitDataInitializer.initializeDataInternal(DbUnitDataInitializer.java:101)
	at com.fidelity.shares.util.datainit.BaseDataInitializer.initializeData(BaseDataInitializer.java:26)
	at com.fidelity.shares.util.datainit.dbunit.DbUnitDataInitializer.initializeData(DbUnitDataInitializer.java:73)
	at com.fidelity.shares.testing.basic.BaseIntegrationTest.setUpData(BaseIntegrationTest.java:55)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
	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.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: FKE909C39B208E3C0B: PUBLIC.ACCOUNT_MANAGER FOREIGN KEY(PRIMARY_ACCOUNT_ID) REFERENCES PUBLIC.ACCOUNT(ID); SQL statement:
update PUBLIC.ACCOUNT_MANAGER set MANAGER_CODE = ?, PARTY_ID = ?, VERSION = ?, PRIMARY_ACCOUNT_ID = ? where ID = ? [23002-114]
	at org.h2.message.Message.getSQLException(Message.java:105)
	at org.h2.message.Message.getSQLException(Message.java:116)
	at org.h2.message.Message.getSQLException(Message.java:75)
	at org.h2.constraint.ConstraintReferential.checkRowOwnTable(ConstraintReferential.java:327)
	at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:269)
	at org.h2.table.Table.fireConstraints(Table.java:761)
	at org.h2.table.Table.fireAfterRow(Table.java:776)
	at org.h2.command.dml.Update.update(Update.java:139)
	at org.h2.command.CommandContainer.update(CommandContainer.java:72)
	at org.h2.command.Command.executeUpdate(Command.java:208)
	at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:175)
	at com.p6spy.engine.logging.P6LogPreparedStatement.execute(P6LogPreparedStatement.java:161)
	at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:169)
	at org.dbunit.database.statement.SimplePreparedStatement.addBatch(SimplePreparedStatement.java:80)
	at org.dbunit.operation.RefreshOperation$RowOperation.execute(RefreshOperation.java:183)
	at org.dbunit.operation.RefreshOperation.execute(RefreshOperation.java:110)
	at com.fidelity.shares.util.datainit.dbunit.DbUnitDataInitializer.initializeDataForDataSet(DbUnitDataInitializer.java:141)
	at com.fidelity.shares.util.datainit.dbunit.DbUnitDataInitializer.initializeDataInternal(DbUnitDataInitializer.java:97)
	... 31 more
1306951950014|0|1|rollback||

DBUnit never inserts the account entry as it tries to do all the account_manager entries first.

Is there a way to disable this sorting feature or is this just how DBUnit is going to work going forward?

Thanks!