2013-07-26 2 views
5

я использую H2 в базе данных памяти для тестирования и моя конфигурация выглядит следующим образом:org.hibernate.PersistentObjectException: отдельностоящий объект передается упорствовать H2 в базе данных памяти

1- SpringTestingConfig:

@Configuration 
@ComponentScan(basePackages = "com.myapp.data", excludeFilters = { @Filter(Configuration.class) }) 
@PropertySource("classpath:/test.properties") 
@Profile("test") 
public class SpringTestingConfig { 
    @Bean 
    public DataSource dataSource() { 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     dataSource.setDriverClassName("org.h2.Driver"); 
     dataSource.setUrl("jdbc:h2:mem:test;MODE=Mysql;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS MYAPP"); 
     dataSource.setUsername("sa"); 
     dataSource.setPassword(""); 
     return dataSource; 
    } 
} 

2- MyTestClass:

@RunWith(SpringJUnit4ClassRunner.class) 
@TestExecutionListeners({ WebContextTestExecutionListener.class, 
     DependencyInjectionTestExecutionListener.class, 
     DirtiesContextTestExecutionListener.class, 
     TransactionalTestExecutionListener.class }) 
@ActiveProfiles("test") 
@DirtiesContext 
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { 
     SpringConfig.class, SpringTestingConfig.class, 
     SpringLocalContainerJPAConfig.class, CustomConfiguration.class }) 
@PrepareForTest({ FacesContext.class }) 
@PowerMockIgnore({ "javax.management.*", "javax.xml.parsers.*", 
    "com.sun.org.apache.xerces.internal.jaxp.*", "ch.qos.logback.*", 
    "org.slf4j.*" }) 
public class MyTestClass{ 

    private Company company; 
    private User user; 


    @Test 
    public void signup(){ 

     User user = new User(); 
    Company company = new Company(); 
    company.setName("Test"); 
    company = usService.saveCompany(company); 
    user.setFirstName("Test"); 
    user.setLastName("User"); 
    user.setEmail("[email protected]"); 
    user.setPassword("verySecret"); 
    user.setCompany(company); 
    user = usService.saveUser(user); // gives exception 

    } 

} 

3- Сохранить методы:

@Transactional(propagation = Propagation.REQUIRED) 
    public User saveUser(User user) { 
     return userRepository.saveAndFlush(user); //JpaRepository 
    } 

@Transactional(propagation = Propagation.REQUIRED) 
    public Company saveCompany(Company company) { 
     return companyRepository.saveAndFlush(company); //JpaRepository 
    } 

4- JPA Config

@Configuration 
@EnableSpringConfigured 
public class SpringJNDIJPAConfig { 
protected static final Logger logger = LoggerFactory.getLogger(SpringConfig.class); 
protected static final String HIBERNATE_TRANSACTION_JTA_PLATFORM = "hibernate.transaction.jta.platform"; 

@Value("${hibernate.naming_strategy:org.hibernate.cfg.DefaultNamingStrategy}") 
private String namingStrategy; 

@Value("${hibernate.packages_to_scan:com.myapp.data.domain}") 
private String packagesToScan; 

@Value("${spring_config.project_name}") 
private String projectName; 

@Value("${hibernate.show_sql:false}") 
private String showSql; 

@Value("${hibernate.hbm2ddl.auto:update}") 
private String hbm2ddlAuto; 

@Value("${hibernate.format_sql:false}") 
private String formatSql; 

@Value("${hibernate.dialect:org.hibernate.dialect.MySQL5InnoDBDialect}") 
private String hibernateDialect; 

@Value("${hibernate.connection.useUnicode:true}") 
private String useUnicode; 

@Value("${hibernate.connection.characterEncoding:UTF-8}") 
private String characterEncoding; 

@Value("${hibernate.charSet:UTF-8}") 
private String charSet; 

@Value("${hibernate.default_schema}") 
private String defaultSchema; 

@Value("${hibernate.use_default_schema:true}") 
private boolean useDefaultSchema; 

@Value("${hibernate.use_sql_comments:true}") 
private String useSqlComments; 

@Autowired 
private ApplicationContext applicationContext; 

@Autowired 
private DataSource dataSource; 

@Bean 
public HibernateExceptionTranslator hibernateExceptionTranslator() { 
    return new HibernateExceptionTranslator(); 
} 

@Bean 
protected EntityManagerFactory entityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean(); 

    JtaPersistenceUnitManager puManager = new JtaPersistenceUnitManager(); 
    Map<String, DataSource> dataSources = new HashMap<String, DataSource>(); 
    dataSources.put("dataSource", dataSource); 
    puManager.setDataSourceLookup(new MapDataSourceLookup(dataSources)); 
    puManager.setDefaultDataSource(dataSource); 
    puManager.setPackagesToScan(packagesToScan()); 
    bean.setPersistenceUnitManager(puManager); 

    bean.setPersistenceProviderClass(HibernatePersistence.class); 
    bean.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); 

    Properties jpaProperties = getHibernateProperties(); 
    jpaProperties.put(HIBERNATE_TRANSACTION_JTA_PLATFORM, SpringJtaPlatform.class.getName().toString()); 
    bean.setJpaProperties(jpaProperties); 

    puManager.afterPropertiesSet(); 
    bean.afterPropertiesSet(); 
    return bean.getObject(); 
} 

protected String getDefaultSchema() { 
    String ds = ConfigurationUtil.config().getString("db.schema.name"); 
    if (ds != null) defaultSchema = ds; 
    return defaultSchema; 
} 

protected String getUseUnicode() { 
     return useUnicode; 
} 

protected String getCharacterEncoding() { 
     return characterEncoding; 
} 

protected String getCharSet() { 
     return charSet; 
} 

protected String getFormatSql() { 
    return formatSql; 
} 

protected String getHbm2ddlAuto() { 
    return hbm2ddlAuto; 
} 

protected String getHibernateDialect() { 
    return hibernateDialect; 
} 

protected Properties getHibernateProperties() { 
    Properties properties = new Properties(); 
    properties.put("hibernate.dialect", getHibernateDialect()); 
    properties.put("hibernate.hbm2ddl.auto", getHbm2ddlAuto()); 
    properties.put("hibernate.show_sql", getShowSql()); 
    properties.put("hibernate.use_sql_comments", getUseSqlComments()); 
    properties.put("hibernate.format_sql", getFormatSql()); 
    if(useDefaultSchema) { 
    properties.put("hibernate.default_schema", getDefaultSchema()); 
    } 
    //properties.put("hibernate.ejb.naming_strategy", namingStrategy); 
    properties.put("hibernate.hbm2ddl.import_files", "/import.sql"); 
    //properties.put("hibernate.connection.characterEncoding", getCharacterEncoding()); 
    //properties.put("hibernate.connection.charSet", getCharSet()); 
    //properties.put("hibernate.connection.useUnicode", getUseUnicode()); 
    if(logger.isInfoEnabled()) { 
    logger.info(MessageFormat.format("SET HIBERNATE PROPERTIES: {0}", properties.toString())); 
    } 
    return properties; 
} 

protected String getProjectName() { 
    return projectName; 
} 

protected String getShowSql() { 
    return showSql; 
} 

protected String getUseSqlComments() { 
    return useSqlComments; 
} 

protected String packagesToScan() { 
     return packagesToScan; 
    } 

@Bean 
protected JtaTransactionManager transactionManager() { 
    SpringBeanFactory.setApplicationContext(applicationContext); 
    JtaTransactionManager manager = new JtaTransactionManager(); 
    manager.setTransactionManagerName("java:jboss/TransactionManager"); 
    manager.setUserTransactionName("java:jboss/UserTransaction"); 
    manager.afterPropertiesSet(); 
    return manager; 
} 

} 

5- Сущность пользователя:

@Entity 
@Table(name = "User", uniqueConstraints = { @UniqueConstraint(columnNames = { 
     "CompanyGID", "MPath" }) }) 
public class User extends PersistableEntity implements UserDetails { 
    /** 
    * 
    */ 
    private static final long serialVersionUID = -6520416613985790209L; 

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
    @JoinColumn(name = "CompanyGID") 
    private Company company; 

НОМЕР: код в методе испытаний работает очень хорошо при запуске приложения (l базы данных OCAL) на Jboss и вызов кода из каркасного метода фасоли, но при запуске из теста (в базе данных памяти) это экономит компанию и при попытке сохранить пользователь это дает исключение:

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.myapp.data.domain.Company; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.myapp.data.domain.Company 
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:668) 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:106) 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403) 
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58) 
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
    at com.myapp.service.UserService.saveUser_aroundBody6(UserService.java:98) 
    at com.myapp.service.UserService$AjcClosure7.run(UserService.java:1) 
    at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:59) 
    at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:65) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260) 
    at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:63) 
    at com.myapp.service.UserService.saveUser(UserService.java:93) 
    at com.myapp.service.UserService$$FastClassByCGLIB$$697e2a1b.invoke(<generated>) 
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631) 
    at com.myapp.service.UserService$$EnhancerByCGLIB$$abc2864a.saveUser(<generated>) 
    at test.myapp.web.controllers.SignUpBeanTest.testSignUp(SignUpBeanTest.java:126) 
    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.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88) 
    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.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.PersistentObjectException: detached entity passed to persist: com.myapp.data.domain.Company 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141) 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:842) 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:835) 
    at org.hibernate.ejb.engine.spi.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:53) 
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:387) 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:330) 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208) 
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165) 
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:424) 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:263) 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:192) 
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:135) 
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78) 
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208) 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151) 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:78) 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:852) 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:826) 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:830) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:875) 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241) 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:354) 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush(SimpleJpaRepository.java:368) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:333) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155) 
    ... 38 more 
+0

некоторых коды отсутствует в вашем тесте. Что такое компания? – ben75

ответ

10

Я думаю, что вопрос находится здесь:

@Test 
    public void signup(){ 

    User user = new User(); 
    Company company = new Company(); 
    company.setName("Test"); 
    company = usService.saveCompany(company); //object is saved and transaction is closed, so company is detached here. 
    user.setFirstName("Test"); 
    user.setLastName("User"); 
    user.setEmail("[email protected]"); 
    user.setPassword("verySecret"); 
    user.setCompany(company); //u are setting this detached object to user, NOTE user object's company attr is cascade.all which means this company will be saved as well when you save user. 
    user = usService.saveUser(user); // gives exception, because you are saving new user object with detached company object. 

    } 

Так как же мы его решаем? Вы можете позволить пользователю сохранить объект компании, так что вы не спасаете компанию явно, так как cascade.all был на для объекта компании в потребителе, компания должна быть сохранена, а когда пользователь спасаемыха:

@Test 
    public void signup(){ 

    User user = new User(); 
    Company company = new Company(); 
    company.setName("Test"); 
    user.setFirstName("Test"); 
    user.setLastName("User"); 
    user.setEmail("tes[email protected]"); 
    user.setPassword("verySecret"); 
    user.setCompany(company); 
    user = usService.saveUser(user); // gives exception 

    } 
+0

ОК, я попробую это, но странно, что эти точные шаги, которые я опубликовал, работают очень хорошо, без проблем в режиме разработки (когда я запускаю приложение на jboss и вызывают метод), но дает только исключение при тестировании идеи? –

+1

Вы правы, что решили проблему, но меня поразило то, что этот неудачный код отлично работает в режиме управляемого bean-действия и только терпит неудачу в тестировании !!!!!!!!!!! 1 –

+0

if 'public void signup() 'отмечен как транзакция, это не сработает. это может быть так. – Elbek

Смежные вопросы