org.hibernate.WrongClassException 当通过具有抽象 class 继承的休眠加载实体时

org.hibernate.WrongClassException when loading entity via hibernate with abstract class inheritance

问题:

我是否需要删除接口 IAbstractUserService 上的泛型?

是否与类型擦除的答案有关?

问题:

我遇到了这个异常:

org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [com.faz.idb.models.Adviser] : loaded object was of wrong class class com.faz.idb.models.Customer

当尝试加载实体时:

T getUserByEmail(String email);

像这样:

AbstractUserServiceImpl<? extends AbstractUser> userService;
AbstractUser user = userService.getUserByEmail(email);

目前我有:

hibernate v7.0.3.Final

抽象 parent class : AbtrsactUser

Child classes:客户和顾问;

@Getter
@Setter
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "user_type", discriminatorType = DiscriminatorType.STRING)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(name = "customer", value = Customer.class),
        @JsonSubTypes.Type(name = "adviser", value = Adviser.class)
})
@DiscriminatorOptions(force = true)
public abstract class AbstractUser { ........ }


@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@DiscriminatorValue("adviser")
@DiscriminatorOptions(force = true)
public class Adviser extends AbstractUser { ........ }


@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@DiscriminatorValue("customer")
@DiscriminatorOptions(force = true)
public class Customer extends AbstractUser { ........ }

服务:

public interface IAbstractUserService<T extends AbstractUser> {
        T getUserByEmail(String email);

实施:

@Service public class AbstractUserServiceImpl<T extends AbstractUser> implements IAbstractUserService<T> {

    @Autowired
    private AbstractUserRepository<T> userRepository;

    @Override
    public T getUserByEmail(String email) {
        return userRepository.findByEmail(email).orElse(null);
    }

存储库:

@存储库 public interface AbstractUserRepository extends JpaRepository { 可选的 findByEmail(String email); }

生成SQL:

Hibernate: select abstractus0_.id as id2_0_, abstractus0_.email as email3_0_, abstractus0_.password as password4_0_, abstractus0_.user_type as user_typ1_0_ from abstract_user abstractus0_ where abstractus0_.user_type in ('adviser', 'customer') and abstractus0_.email=?

Hibernate: select person0_.customer_id as customer1_5_0_, person0_.first_name as first_na2_5_0_, person0_.gender as gender3_5_0_, person0_.last_name as last_nam4_5_0_, adviser1_.id as id2_0_1_, adviser1_.email as email3_0_1_, adviser1_.password as password4_0_1_ from person person0_ left outer join abstract_user adviser1_ on person0_.customer_id=adviser1_.id where person0_.customer_id=? 2022-03-14 06:14:34.029

INFO 79095 --- [nio-8080-exec-2] o.h.e.internal.DefaultLoadEventListener : HHH000327: Error performing load command

在我的数据库中我只有一个用户:

user_type |编号 |电邮 |密码

客户 | 1 | xyz@live.fr | ....

问题已解决。

我在@OneToOne 关系的子实体中使用不带@JoinColumn(name="id") 的@MapsId。

解释:

“AbstracUser”由“Customer”实体扩展,他与“PersonDetails”有@OneToOne 关系。

所以在客户中我有:

@OneToOne(mappedBy = "Customer", fetch = FetchType.LAZY, 
cascade {CascadeType.ALL}, optional = false)  
@PrimaryKeyJoinColumn  private PersonDetails person;

和人物详细信息:

@MapsId()
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name="id")
private Customer customer;

解决方案是在

中添加引用的列
@MapsId("id")

@MapsId
@JoinColumn(name="id")

N.B

  • 还要确保通过“设置”相应的对象来同步关系的双方。 (ressource I used)
  • 为了更好的架构,我最终将 @OneToOne 关系放在“AbstractUser”实体中(而不是在 Customer 中)。