Расширение таблицы Hibernate-наследования (TABLE_PER_CLASS)

У меня есть две таблицы: UserExtended наследуется от User, Но я не могу рекламировать существующий User в UserExtended,

Объекты:

@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
}

Обслуживание:

// 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
    }
}

С этим кодом я получаю исключение: SQLServerException: Cannot insert the value NULL into column 'email', table 'User'; column does not allow nulls. INSERT fails так как email столбец не является нулевым в БД.

Когда я раскомментирую строку userExt.setEmail(user.getEmail()); Я получаю еще одно исключение SQLServerException: Cannot insert duplicate key row in object 'User' with unique index 'UQ_User_email'. The duplicate key value is (xxx@mail.com) так как email должен быть уникальным.

Я могу сделать вставку с простым SQL как INSERT INTO UserExtended (id) VALUES (13); Как я могу сделать то же самое, используя Hibernate и Spring Data JPA?

1 ответ

Решение

Вы не можете иметь два разных объекта одного типа (UserExtended это User) и с тем же идентификатором (и тем же адресом электронной почты, в вашем случае). Так что это не может работать. Так же, как в Java, объект имеет один-единственный конкретный тип и не может стать чем-то другим.

Вы должны будете сначала удалить пользователя (который, конечно, может нарушить множество ограничений FK), прежде чем воссоздать его с другим подтипом.

Наследование не является мудрым выбором здесь. Вместо этого вы должны использовать композицию: пользователь имеет (или не имеет) UserExtension.

Другие вопросы по тегам