3

I have 2 entities - User and Role with mapping @ManyToOne. I want to change role in user, but Role want's to be updated too.

User entity:

@ManyToOne
@JoinColumn(name = "role_id", insertable =  false, updatable = false)
private Role role;

role entity:

@OneToMany(mappedBy = "role")
private Set<User> users;

The error I get is:

java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance beforeQuery flushing: com.spring.model.Role at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:144) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162) at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1434)

My tables in DB are not set with CASCADE UPDATE or INSERT. I wasn't able to find appropriate solution. Thanks for your help

EDIT:

This is how I update User

public void update(User user) {
        User entity = dao.findById(user.getId());
        if(entity!=null) {
            entity.setRole(user.getRole());
        }
    }

EDIT2:

My hibernate configuration

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.spring.configuration" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {

    @Autowired
    private Environment environment;

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.spring.model" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
        return dataSource;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        return properties;        
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) {
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    }
}
evelyn
  • 31
  • 1
  • 6

1 Answers1

0

You should use the cascade attribute of the OneToMany annotation, it does not have any relationship with the database cascade operations (but can be affected by that).

@OneToMany(cascade = CascadeType.ALL, mappedBy="role", orphanRemoval = true)
private Set<User> users;

This way the operation will be propagated to the collection elements. You can check this answer for more info.

You can also modify the cascade property of the ManyToOne annotation.

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "role_id")
private Role role;
Jose Da Silva
  • 3,536
  • 3
  • 22
  • 34
  • No, it is still the same. – evelyn Mar 27 '18 at 02:38
  • shouldn't you remove `updatable = false` from the `@JoinColumn`? – Jason White Mar 27 '18 at 02:40
  • 1
    I copy them by accident, yes they should be removed – Jose Da Silva Mar 27 '18 at 02:40
  • Should I try to change tables in DB with no update and no insert? I am adding my hibernate java configuration – evelyn Mar 27 '18 at 02:41
  • Even if I remove updatable = false, error still persist – evelyn Mar 27 '18 at 02:46
  • Try removing `insertable=false`. – Madhusudana Reddy Sunnapu Mar 27 '18 at 02:51
  • Do you have exactly this? `@ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "role_id") private Role role;` – Jose Da Silva Mar 27 '18 at 02:52
  • if I have exactly @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "role_id") and @OneToMany(cascade = CascadeType.ALL, mappedBy="role", orphanRemoval = true) then Role is being updated too – evelyn Mar 27 '18 at 05:34
  • OK, I find out I can't update table ROLE with NO UPDATE, because I am updating not primary key from USER . When I update entities with cascade types and orphanremoval, my table ROLE is updated with new rows and USER is updated with new key from table ROLE. I am being quite desperate here ... – evelyn Mar 27 '18 at 06:42
  • Where did you had specified `NO UPDATE`? – Jose Da Silva Mar 27 '18 at 14:40
  • Nowhere, I wanted to update my tables in DB with ON DELETE NO ACTION. But it is not possible with design of my tables I have. I am not going to use annotations for entities and update each separately. thank you for your help – evelyn Mar 27 '18 at 18:28
  • You're welcome, anyway the normal case it to use `NO ACTION` in the database since hibernate handles that for you. – Jose Da Silva Mar 27 '18 at 18:58