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?
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.