JPA(Hibernate):在通用@MappedSuperclass中使用@EmbeddedId时出错

Dom*_*nic 5 java spring hibernate jpa

我目前正在为遗留数据库定义 JPA 实体(大量复合键,但也有单列键)。我创建了以下实体超类:

@MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> {
    public abstract ID getId();
    public abstract void setId(ID id);
}
Run Code Online (Sandbox Code Playgroud)

然后是复合键的超类(以及长主键的超类,此处未列出):

@MappedSuperclass
public abstract class AbstractEmbeddedIdEntity<ID extends Serializable> extends AbstractEntity<ID> {
    @EmbeddedId
    private ID id;

    public AbstractEmbeddedIdEntity() {
        id = newId();
    }

    @Override
    public ID getId() {
        return id;
    }

    @Override
    public void setId(ID id) {
        this.id = id;
    }

    protected abstract ID newId();
}
Run Code Online (Sandbox Code Playgroud)

最后是这样的具体实体:

@Entity
@Table(name = "firstEntity")
public class FirstEntity extends AbstractEmbeddedIdEntity<FirstEntityId> {

    public FirstEntity() {
    }

    @Embeddable
    public static class FirstEntityId implements Serializable {
        @Column(name = "firstId")
        private String firstId;

        public FirstEntityId() {
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (!(obj instanceof FirstEntityId)) {
                return false;
            }
            FirstEntityId other = (FirstEntityId) obj;
            return 
                    Objects.equals(firstId, other.firstId);
        }

        @Override
        public int hashCode() {
            return Objects.hash(firstId);
        }
    }

    @Override
    protected FirstEntityId newId() {
        return new FirstEntityId();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在的问题是,如果我有多个这样的实体并尝试访问实体的 ID 属性(当前使用 Spring Boot,例如findByIdFirstId(String firstId)),则会引发异常:

java.lang.IllegalArgumentException: Unable to locate Attribute  with the the given name [firstId] on this ManagedType [unknown]
Run Code Online (Sandbox Code Playgroud)

我对此进行了调试,发现在休眠中,元模型将我的所有实体映射到同一个 MappedSupperclass 实例。在应用程序启动期间,@EmbeddedId返回的newId()被设置为MappedSupper类,覆盖先前实体的ID。所以最后,所有实体都映射到同一个MappedSupper类,但是MappedSupper类只有@EmbeddedId最后一个实体的。

在上面的示例中,访问 ID 属性失败,因为@EmbeddedId最后一个实体的 ID 属性没有名为“firstId”的属性(它已被最后一个实体的 ID 属性覆盖)。

现在我想知道我的方法是否错误,我是否遗漏了某些内容或者这是否可能是休眠的问题?

github 上提供了使用 spring boot 的完整示例。运行与mvn spring-boot:run.

Dom*_*nic 1

在我看来,这就像休眠中的错误,因此我在休眠错误跟踪器中创建了一个票证。作为解决方法,我现在在 concreate 实体类而不是抽象超类中定义 ID 属性 (@EmbeddedId)。