0

I have following domain mapping:

@Entity
@Table(name = "terminal_admin_role")
public class AdminRole {

    @Id
    @Column(name = "role_id", nullable = false, unique = true)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id")
    @SequenceGenerator(name = "user_id", sequenceName = "user_id")
    private Long adminId;

    @Column(name = "role")
    private String role;

    public AdminRole(String role) {
        this.role = role;
    }

    public AdminRole() {
    }

    // get set

    @Override
    public String toString(){
        return role;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof AdminRole)) {
            return false;
        }

        AdminRole adminRole = (AdminRole) o;

        if (!role.equals(adminRole.role)) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        return role.hashCode();
    }
}

and

@Entity
@Table(name = "terminal_admin")
public class TerminalAdmin {
    @ManyToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
    @JoinTable(name = "admin_role", joinColumns = { 
        @JoinColumn(name = "admin_id", nullable = false) }, 
        inverseJoinColumns = { @JoinColumn(name = "role_id", 
                nullable = false) })
    private Set<AdminRole> adminRoles;      
    //...
}

and following code to execute:
controller:

@RequestMapping(value = "/admin/addNewAdmin")
public String adminUsers(@ModelAttribute @Valid TerminalAdmin terminalAdmin,
        BindingResult bindingResult, ModelMap model, Principal principal, HttpSession session) {
    ...
    terminalAdmin.setCreateDate(Calendar.getInstance());
    terminalAdminService.saveTerminalAdmin(terminalAdmin);
    ...
 }

service:

@Override
@Transactional
public void saveTerminalAdmin(TerminalAdmin newAdmin) {
    String rawPassword = newAdmin.getPassword();
    newAdmin.setPassword(passwordEncoder.encode(newAdmin.getPassword()));
    terminalAdminDao.save(newAdmin);
    emailService.sendAdminCreatedEmail(rawPassword, newAdmin.getEmail(), newAdmin.getAdminRoles());
    emailService.sendAdminRegisteredForAdminEmail(newAdmin);
}

dao:

@Override
@Transactional
public void save(TerminalAdmin terminalAdmin) {
    sessionFactory.getCurrentSession().save(terminalAdmin);
}

After it I see that admin roles binded to user duplicated in AdminRole table in database.

What Do I wrong? I have wrote equals method.

P.S.

before saving in debug I see following values:

enter image description here

gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • It looks confusing to me: your `AdminRole` mapped to table `terminal_admin_role`, while the table `admin_role` is actually the join table for `TerminalAdmin` vs `AdminRole` (which means for tables `terminal_admin` vs `terminal_admin_role`). `AdminRole`'s ID col named `role_id` but is actually `user_id` for sequence name, that means Admin is not a user but a role is more like a user? Can the design be cleaned up to be a sane one? :P – Adrian Shum Oct 28 '15 at 07:25
  • and what's the meaning of `After it I see that admin roles binded to user duplicated in AdminRole table in database.` ? you see duplicated `AdminRole` created in DB (in `terminal_admin_role` table)? or you see duplicated relationships in `admin_role` table? (see how confusing your naming is? :P ) – Adrian Shum Oct 28 '15 at 07:28
  • @Adrian Shum **you see duplicated AdminRole created in DB (in terminal_admin_role table)?** - yes – gstackoverflow Oct 28 '15 at 07:30
  • For the `TerminalAdmin` coming in to controller, are the `AdminRole`s containing proper ID? If not, that's just normal as Hibernate will treat every incoming AdminRole being a new one – Adrian Shum Oct 28 '15 at 07:40
  • @Adrian Shum But I provide equals method which doesn't use id – gstackoverflow Oct 28 '15 at 07:41
  • admin roles from controller doesn't contains id – gstackoverflow Oct 28 '15 at 07:42
  • Hibernate does not work like this. `ID` field is the identity of a persisted entity. – Adrian Shum Oct 28 '15 at 07:42
  • @Adrian Shum do you suggest make request to database and add ids ? – gstackoverflow Oct 28 '15 at 07:45
  • I suggest you to get a book of Hibernate and learn the basics first, and also remodel your entities to make it less confusing. It is just so dangerous for someone don't even know the importance of ID field to continue developing on Hibernate/JPA, and it is actually more dangerous with such kind of confusing entity design – Adrian Shum Oct 28 '15 at 07:50

1 Answers1

1

Because in your new TerminalAdmin, the AdminRole it is referring does not contain ID. ID is the identity of entities. It does not use equals() to identify the identity. Without IDs, Hibernate simply treat it as a new AdminRole to be persisted to DB (as you have set corresponding cascade options in TerminalAdmin)

There are some choices you may take

  1. Change the ID of your AdminRole to the role String, or/and
  2. Lookup the correct AdminRole by role string, and set them in your new TerminalAdmin entity, or/and
  3. Contains the AdminRole ID in the incoming request, etc...
Adrian Shum
  • 38,812
  • 10
  • 83
  • 131