简体   繁体   中英

Magic update entity in Hibernate with Spring using jUnit

i have a web project where is use Spring 3.1.1.RELEASE, Hibernate 4.2.0.Final , mysql version '5.5.19-enterprise-commercial-advanced-log' and junit 4.7

I'm doing my unit testing, i test my CRUD operations.

I made several test and almost all are fine, the problem is in group-event relationship, in update test, i want create a group and many events , set the list ( HashSet in the strict sense) a send the group to the service, likewise the update method. Create works fine, but not update :(

Classes

public class Group implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private Integer groupID;    
    private User user;
    private Integer userID; 
    private User userManegement;
    private Integer userManagementID;   
    private Date deteIni;
    private Set<Event> events;
    private Set<StatusGroup> status;

    //get 
    //set
    ....

public class Event implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private Integer eventID;
    private Integer groupID;
    private Date dateIni;
    private Date dateTwo;
    private String help;
    private String commet;
    private Group group;
    //get
    //set
    ......

Mapping

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 18/03/2014 09:58:25 AM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.my.dev.mysql.Group" table="Group">
        <id name="groupID" type="java.lang.Integer">
            <column name="id_group" />
            <generator class="identity" />
        </id>
        <many-to-one name="user" column="user_id" foreign-key="id_user" class="com.my.dev.mysql.User" 
            fetch="join" update="false" insert="false">            
        </many-to-one>
        <property name="userID" type="java.lang.Integer">
            <column name="user_id" />
        </property>
        <many-to-one name="userManegement" column="user_management_id" foreign-key="id_user" class="com.my.dev.mysql.User"
         fetch="join" update="false" insert="false">
        </many-to-one>       
        <property name="userManagementID" type="java.lang.Integer">
            <column name="user_management_id" />
        </property>
        <property name="deteIni" type="java.util.Date">
            <column name="dete_ini" sql-type="DATE" not-null="true" />
        </property>

        <set name="events">
            <key>
                <column name="group_id" />
            </key>
            <one-to-many class="com.my.dev.mysql.Event" />
        </set>
        <set name="status">
            <key>
                <column name="group_id" />
            </key>
            <one-to-many class="com.my.dev.mysql.StatusGroup" />
        </set>
    </class>
</hibernate-mapping>

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 18/03/2014 09:58:25 AM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.my.dev.mysql.Event" table="EVENT">
        <id name="eventID" type="java.lang.Integer">
            <column name="id_event" />
            <generator class="identity" />
        </id>
        <property name="groupID" type="java.lang.Integer" not-null="true">
            <column name="group_id" />
        </property>
        <property name="dateIni" type="java.util.Date" not-null="true">
            <column name="date_ini" sql-type="TIMESTAMP" not-null="true" />
        </property>
        <property name="dateTwo" type="java.util.Date" not-null="true">
            <column name="date_two" sql-type="TIMESTAMP" not-null="true" />
        </property>
        <property name="help" type="java.lang.String">
            <column name="help" not-null="true" />
        </property>
        <property name="commet" type="java.lang.String">
            <column name="commet" not-null="true" />
        </property>
        <many-to-one name="group" column="group_id" foreign-key="id_group" class="com.my.dev.mysql.Group"
            fetch="join" update="false" insert="false">           
        </many-to-one>
    </class>
</hibernate-mapping>

My Unit Test

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({ TransactionalTestExecutionListener.class, DependencyInjectionTestExecutionListener.class })
@ContextConfiguration(locations = { "/testEnvironment.xml" })
public class GroupServiceImplTest {

    @Autowired
    private GroupService groupService;

    @Test //THIS TEST WORKS FINE
    public void create() {

        FormBeanGroup form = new FormBeanGroup();
        form.setDate("24/03/2014");

        List<Event> events = new ArrayList<Event>();
        for (int i = 0; i < 8; i++) {
            Event event = new Event();
            event.setHelp("help -" + Randomizer.getNumSRandom());
            event.setDateTwo(Calendar.getInstance().getTime());

            Calendar now = Calendar.getInstance();
            now.set(Calendar.DAY_OF_YEAR, now.get(Calendar.DAY_OF_YEAR) - i);
            event.setDate(now.getTime());
            event.setCommet("ubicacion ");

            events.add(event);
        }

        form.setEvents(events);

        try {
            groupService.save(form);
        } catch (GenericException e) {

            e.printStackTrace();
        }

    }


    @Test //THIS TEST WORKS FINE
    public void get(){
        Group group = groupService.getById(40);
        System.out.println(group);
        assertNotNull(group); 

        assertEquals(group.getStatus().get() , TypeGroup.ALFA);
    }


    @Test //THIS TEST WORKS FINE
    public void delete(){
        groupService.borrarEvents(41);
    }

    @Test // f*****in TEST
    public void update() {

        FormaCapturaGroup form = new FormaCapturaGroup();
        form.setDate("24/03/2014");
        form.setId(40);

        List<Event> events = new ArrayList<Event>();
//      for (int i = 0, k = 250; i < 8; i++, k++) { //fill events, but i comment, trying to find the error

        form.setEvents(events);

        try {
            groupService.update(form);
        } catch (GenericException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

The service

@Transactional
public void update(FormBeanGroup form) throws GenericException {
    Group group = groupDao.getById(form.getId());
    if (group != null) {

        //more code comment beacuse i trying to find the error


        group.setEvents(new HashSet<Event>(form.getEvents())); //fix chrome grammar spelling


        groupDao.update(group);
        System.out.println("post");
    }
}

The dao

public Group update(com.segurosargos.siga.modelo.mysql.Group group)
            throws GenericException {

        System.out.println("DAO{Update} ");
        System.out.println(group);

        //really 100 lines commet
                //Believe me seriously.
                //this is all code in update method

        return null;
    }

When i run the test update throws this error:

org.springframework.dao.DataIntegrityViolationException: could not perform addBatch; SQL [update EVENT set group_id=null where group_id=?]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not perform addBatch
    at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:159)
    at org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:606)
    at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:488)
    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 $Proxy18.update(Unknown Source)
    at com.my.dev.service.impl.GroupServiceImplTest.update(AgendaServiceImplTest.java:129)
    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.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    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:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    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.hibernate.exception.ConstraintViolationException: could not perform addBatch
    at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:128)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
    at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:114)
    at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.doExecuteBatch(BatchingBatch.java:101)
    at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.execute(AbstractBatchImpl.java:149)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.executeBatch(JdbcCoordinatorImpl.java:198)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:357)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:277)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:328)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1233)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:403)
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
    at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:480)
    ... 36 more
Caused by: java.sql.BatchUpdateException: Column 'group_id' cannot be null
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1666)
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1082)
    at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:110)
    ... 48 more

And log

post
Hibernate: 
    update
        EVENT 
    set
        group_id=null 
    where
        group_id=?
WARN : org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1048, SQLState: 23000
ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Column 'group_id' cannot be null

Yes group_id is NOT NULL but Why this update occurs? .

While testing my code comment much, provided each time this exception was produced, which he attributed to him something I had done. but not.

In fact change the column to accept null, and my test worked well, both within my unit test and database were restated things right.

I keep wondering why this happens, this magical update I never do , is what I'm doing wrong, please I need your help.

The problem is that when this instruction is executed:

group.setEventos(new HashSet<Evento>(form.getEventos()));

there are new events linked to the group. This means that the events previously linked to the group are no longer linked it to it anymore.

In order to break this link in the database Hibernate needs to update the foreign key EVENT.group_id to null, and that is the reason why the update is made.

The events previously linked to the group will go on existing as separate entities in the database, without being attached to any group.

This is because Event is an @Entity and not an @Embeddable , so it can exist without being related to a Group . But setting the foreign key column to not-nullable sort of goes against this and causes Hibernate to try to update a non nullable column.

The mapping then needs to be updated either to make Event an @Embeddable that cannot exist without a group, or declare the foreign key as nullable.

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