Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Проблемы сохранения графа объектов с циклами


Автор: coffius 28.2.2011, 15:09
Здравствуйте, помогите разобраться с проблемой.
Есть структура данных, которая представляет своего рода граф объектов, и надо эту структуру данных сохранить в БД.

Данные представлены след. классами:
Код

@Entity
public class SimObj {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    //....

    @LazyCollection(LazyCollectionOption.FALSE)
    @OneToMany(cascade = CascadeType.ALL)
    private List<SimObjField> simFields;
    
    @LazyCollection(LazyCollectionOption.FALSE)
    @OneToMany(cascade = CascadeType.ALL)
    private List<SimObjListField> simListFields;
}

@Entity
public class SimObjField implements IField<SimObj>{
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    private String name;

    @OneToOne(cascade=CascadeType.ALL)
    private SimObj value;
}

@Entity
public class SimObjListField implements IField<List<SimObj>>{
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    private String name;
    
    @LazyCollection(LazyCollectionOption.FALSE)
    @OneToMany(cascade = CascadeType.ALL)
    private List<SimObj> simList;
}


Причем граф имеет циклы, т.е. имеются связи вида: simObj #1 -> simField #1 -> simObj #2 -> simField#2 -> simObj #1. Также бывает, что simObj #1 ссылается на simObj #2 несколько раз.
Т.е одновременно существуют связи:
simObj #1 -> simField #1(имя: parent) -> simObj #2
simObj #1 -> simField #3(имя: sector) -> simObj #2

Тестирование происходит след. образом:
Генерируется граф объектов, причем всегда есть своего рода корневой узел, от которого существует путь до любого другого узла.
Далее этот корневой узел сохранятся в БД c использованием spring и hibernate таким образом:

Код

@Transactional
public Long save(SimObj anElement) throws DAOException,IllegalArgumentException {
    Session session = getSession(); //hibernate session
    return (Long) session.save(anElement);
}


И при попытке сохранения возникает ошибка:
Код

org.springframework.dao.DataIntegrityViolationException: could not insert collection: [org.stl.optimus.db.persist.SimObjListField.simList#2]; SQL [insert into SimObjListField_SimObj (SimObjListField_id, simList_id) values (?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert collection: [org.stl.optimus.db.persist.SimObjListField.simList#2]
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:637)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy21.save(Unknown Source)
    at org.stl.optimus.tests.db.SaveSpaceTest.test(SaveSpaceTest.java:59)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
    at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
    at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
    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.hibernate.exception.ConstraintViolationException: could not insert collection: [org.stl.optimus.db.persist.SimObjListField.simList#2]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1243)
    at org.hibernate.action.CollectionRecreateAction.execute(CollectionRecreateAction.java:58)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:188)
    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:1216)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
    ... 30 more
Caused by: java.sql.BatchUpdateException: Duplicate entry '6' for key 'simList_id'
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2018)
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
    at com.p6spy.engine.logging.P6LogPreparedStatement.executeBatch(P6LogPreparedStatement.java:329)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    at org.hibernate.jdbc.BatchingBatcher.addToBatch(BatchingBatcher.java:56)
    at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1206)
    ... 40 more


База перед сохранением данных пуста.
В одной транзакции сохраняется примерно 3500 объектов. Когда экспериментировал с небольшим числом объектов(около 10) таких проблем не возникало
Копание интернетов результата не принесло. Пробовал менять алгоритмы генерации ID - тоже не помогло.
Вопрос: можно ли  в принципе сохранять такие данные? и как найти проблемное место? 

P.S. методы equals() и hashCode не переопределял.

Автор: LSD 1.3.2011, 12:44
Попробуй переопределить методы equals() и hashCode() и заменить List на Set.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)