Search code examples
javahibernatesql-server-2012spring-data-jpatable-per-class

Hibernate inheritance (TABLE_PER_CLASS) table expansion


I have two tables: UserExtended inherits from User. But I can't promote an existing User to UserExtended.

Entities:

@Entity
@Table
@Inheritance(strategy = InheritanceType.JOINED)
public class User {
   // columns: id, email, etc.
}

@Entity
@Table
@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id")
public class UserExtended extends User {
   // columns
}

Service:

// Repositories
@Autowired
private UserDao userDao;
@Autowired
private UserExtendedDao userExtendedDao;

public void promoteUser() {
    User user = userDao.getUserByEmail(email);
    UserExtended userExt;

    if (user != null) {
        if (user instanceof UserExtended) {
            // cast UserExtended
            userExt = (UserExtended) user;
        } else {
            // extend User to UserExtended
            userExt = new UserExtended();
            userExt.setId(user.getId());
            // userExt.setEmail(user.getEmail());
            userExt = userExtendedDao.save(userExt);    // exception here!
        }
    } else {
        // create new UserExtended
    }
}

With this code I get exception : SQLServerException: Cannot insert the value NULL into column 'email', table 'User'; column does not allow nulls. INSERT fails because email column is not null in DB.

When I uncomment the line userExt.setEmail(user.getEmail()); I get another exception SQLServerException: Cannot insert duplicate key row in object 'User' with unique index 'UQ_User_email'. The duplicate key value is ([email protected]) because email should be unique.

I can do the insertion with plain SQL as INSERT INTO UserExtended (id) VALUES (13); How can I do the same using Hibernate and Spring Data JPA?


Solution

  • You may not have two different entities of the same type (a UserExtended is a User) and with the same ID (and the same email, in your case). So that can't work. Just like, in Java, an object has one and only one concrete type, and can't become something else.

    You would have to first delete the user (which of course can break a lot of FK constraints) before recreating it with another sub-type.

    Inheritance is not a wise choice here. You should instead use composition: a user has (or doesn't have) a UserExtension.