JPA Table 每个 Class 具有不同 Id 名称的继承

JPA Table per Class Inheritance with different Id names

我有以下映射:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle {
    @Id
    @GeneratedValue
    Long id;
}

@Entity
@Table(name = "car")
@AttributeOverride(name = "id", column = @Column(name = "car_id"))
public class Car extends Vehicle {
}

@Entity
@Table(name = "bus")
@AttributeOverride(name = "id", column = @Column(name = "bus_id"))
public class Bus extends Vehicle {
}

我想要实现的是查询不同的表以检索 CarBus 实体。为此,我创建了以下 Spring 数据存储库

public interface VehicleRepository extends CrudRepository<Vehicle, Long> {
}

并尝试像这样使用它:vehicleRepository.findAll();

然而,在这种情况下,我得到 java.sql.SQLSyntaxErrorException: ORA-00904: "KEY": invalid identifier。似乎将 @Inheritance@AttributeOverride 一起用于 @Id 字段不起作用。

我想指出的是,如果 CarBus 实体对 @Id 具有相同的映射,它将完美地工作(但事实并非如此:"car_id" 和 "bus_id")

此外,我尝试将 @Id 字段从 Vehicle class 移动到 subclasses,但结果是每个 @Entity应该包含 @Id.

我想提的另一件事是我尝试使用 @MappedSuperclass 而不是 @Inheritance 但在这种情况下我无法使用 abstact Vehicle 进行查询类型。

有人可以帮我吗?

谢谢

你说,

And what I'm trying to achieve is to query different tables for retrieving both Car and Bus entities.

,但作为第一个考虑,你应该评估你是否真的想这样做。想想这个:

  • 单table 继承策略对于您想象的整个层次结构查询通常是最快的。它可以通过单个查询执行整个层次结构和具体实体操作,无需连接或联合。

  • 单table和联合继承策略确保层次结构中的所有实体都有不同的键,table-per-[不一定如此。 =82=]策略。

  • 单table和联合继承策略促进了涉及抽象超class的关系; table-per-class 策略没有很好地支持这些。

  • 对 table-per-class 策略的支持是 可选。 JPA 提供者不需要支持它,实际上 GlassFish 参考实现中的默认提供者不支持它。因此,不能保证依赖 table-per-class 的应用程序是 portable。 (您的提供商 Hibernate 确实支持它。)

你接着说,

However, in this case I get java.sql.SQLSyntaxErrorException: ORA-00904: "KEY": invalid identifier. Seems like using @Inheritance together with @AttributeOverride for @Id field doesn't work.

@AttributeOverride 仅指定用于覆盖映射的超classes 的属性以及嵌入式classes 的字段和属性。如果 属性出现在这些上下文中,它 @Id 属性有效。对于从实体 superclass 继承的持久字段和属性,它没有指定工作(虽然也没有指定 not 工作),但请注意它 不能使用单table或联合继承策略来处理此类属性。

如果 @AttributeOverride 确实对您有用,那么该用途将是非 table。另一方面,JPA 没有别的东西可以完成你想要的。一个特定的持久性提供者可以有一个支持它的扩展,但 Hibernate 历史上没有这样做——从实体 superclass 继承的所有属性都映射为相同的名称。

你还说,

One more thing I'd like to mention is that I've tried using @MappedSuperclass instead of @Inheritance but in this case I'm not able to query with abstact Vehicle type.

JPA 不为您的特定需求组合提供解决方案:

  • 将每个具体实体 class 映射到单独的 table、
  • 将 ID 命名为每个实体中的不同列名称 table,并且
  • 支持抽象超类型的多态查询。

如果您不愿意更改其中任何一个,那么您将不得不依赖于扩展。在这种情况下,您很幸运:Hibernate 支持 polymorphic queries,其中多态类型未映射为实体。因此,如果您愿意让您的应用程序明确依赖于 Hibernate,您可能会达到您想要的效果。

具体来说,要在 Hibernate 中执行此操作,您将依赖 "implicit polymorphism"。为此,您将避免将 superclass 映射为实体,根据您的经验,我猜它也不应该是映射的 superclass。它可以是一个普通的 class,尽管它的属性不会持久,或者您可以使用一个接口来代替。如果您的 Vehicle class 具有您想要持久化的属性,那么您可以将其更改为可嵌入的 class。您还可以注释每个车辆实体以指定隐式多态性,例如:

@Entity
@Polymorphism(type = PolymorphismType.IMPLICIT)
// ...
public class Car implements Vehicle {
    // ...
}

Hibernate 文档声称隐式多态性是默认设置,但为了清楚起见,我还是建议应用 @Polymorphism 注释。