2

I am trying to implement basic user/roles

A user can have zero to many roles.

public enum Role {
  ROLE_USER,
  ROLE_ADMIN;
}

@Entity
@Table(name = "USERS")
public class User implements Serializable {

  private static final long serialVersionUID = 2936736450886451500L;
  private Long id;
  private Individual individual;
  private Set<Role> roles = new HashSet<Role>();

  @Id
  @Column(name = "ID")
  @GeneratedValue
  public Long getId() {
    return id;
  }

  @SuppressWarnings("unused")
  private void setId(Long id) {
    this.id = id;
  }

  @ElementCollection(targetClass=Role.class)
  @JoinTable(name = "USER_ROLES", joinColumns = @JoinColumn(name = "USER_ID"))
  @Enumerated(EnumType.STRING)
  @Column(name = "role", nullable = false)
  public Set<Role> getRoles() {
    return roles;
  }

  public void setRoles(Set<Role> roles) {
    this.roles = roles;
  }

  public void addRole(Role role) {
    roles.add(role);
  }

}

My Unit Test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/META-INF/spring/resources/resource-context.xml", "classpath:/META-INF/spring/services/persistence-context.xml"})
public class UserDaoJpaImplTest {

@Autowired
UserDao userDao;

@Transactional
@Test
public void testCreate() {
    User user = new User();
    user.setIndividual(new Individual());
    user.addRole(Role.ROLE_USER);
    user.addRole(Role.ROLE_ADMIN);
    userDao.create(user);

    Assert.assertNotSame(user.getId(), 0);
}

the problem is, that jpa (backed by hibernate), is not doing the insert on the USER_ROLES table (it is creating it correctly, with the correct composite PK (ROLE, USER_ID), and FK to user.

I can see in the console, that only a single insert is being done, on the user

Hibernate: insert into USERS (INDIVIDUAL_ID) values ( ? )
Hibernate: insert into INDIVIDUALS values ( )

I assume I am just missing something simple.

kabal
  • 2,085
  • 4
  • 29
  • 43

1 Answers1

4

Elements of collection are inserted into database during flush of persistence context. By default SpringJUnit4ClassRunner triggers a rollback after @Transactional test, therefore automatic flush upon transaction commit doesn't happen.

You need to override this behaviour with @Rollback(false) or @TransactionConfiguraton(defaultRollback = false), or just trigger an explicit flush using flush() method.

Also if you need to override default properties of collection table you should use @CollectionTable, not @JoinTable.

axtavt
  • 239,438
  • 41
  • 511
  • 482
  • Thank you very much, I thought I as going crazy. I guess this shows a slight drawback in doing this kind of TDD (I use that term loosely), in that the test is not "accurate", ie, I dont not want the test after the fact to persist. At least I know what/why it was happening – kabal Apr 19 '12 at 12:58
  • 1
    Explicitly calling flush is not enough, you have to set the transaction configuration to actually commit the data. Otherwise, the transaction will be rolled back and flush will not have persisted anything. – Leonel Jun 14 '12 at 19:45