Java 用SQL替换JPA/Hibernate鉴别器列

Java 用SQL替换JPA/Hibernate鉴别器列,java,hibernate,jpa,Java,Hibernate,Jpa,我必须维护一些用于管理一些数据库表的JPA/Hibernate代码。我有这样的类层次结构: @Entity @Table(name="table_name") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="column_name", discriminatorType=DiscriminatorType.STRING) public abstract class AbstractBas

我必须维护一些用于管理一些数据库表的JPA/Hibernate代码。我有这样的类层次结构:

@Entity
@Table(name="table_name")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="column_name", discriminatorType=DiscriminatorType.STRING)
public abstract class AbstractBaseClass {...}

@Entity
@DiscriminatorValue("N")
public class SubClass1 extends AbstractBaseClass { ...}

@Entity
@DiscriminatorValue("Y")
public class SubClass2 extends AbstractBaseClass { ...}

这一切工作正常,但数据库正在重新设计,歧视性列将被删除,记录的类型将由SQL查询确定。这种重新设计不是我的主意,我无法控制数据库结构。由于现有的代码库,更改Java层次结构也不切实际。我可以用什么来代替鉴别器Column/Discriminator Value,这样一切都可以继续工作?

如果您对表格设计没有任何影响,并且未来的设计会让人大吃一惊,那么情况看起来很糟糕:

但是,也许您仍然可以使用您的实体进行一些小的更改。好消息是,JPA除了单_表连接和每_类表_之外,还提供了另外两种继承映射模型

JOINED:最终将有三个表,每个实体一个表,包括抽象表。这些表将精确地包含各个类中包含的属性。要访问不同的类型,提供程序必须访问和连接不同的表,因此不需要鉴别器列

TABLE_PER_类:您将有两个表,每个表对应一个具体的子类。它们中的每一个都将映射抽象父类的所有属性以及它们自己的属性。与以前一样,提供者将使用单独的表,因此不需要鉴别器

为了进行转换,您必须更改线条

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
要么

@Inheritance(strategy=InheritanceType.JOINED)

JPQL查询的好处是它们根本不需要更改。只需使用JPQL TYPE关键字,提供者就会完成所有映射

编辑:还有一件事-如果您必须处理单个表,但没有鉴别器,并且类型将由联接确定,您可以使用如下JPQL构造函数表达式:

@Entity
@Table(name="table_name")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="column_name", discriminatorType=DiscriminatorType.STRING)
public abstract class AbstractBaseClass {...}

@Entity
@DiscriminatorValue("N")
public class SubClass1 extends AbstractBaseClass { ...}

@Entity
@DiscriminatorValue("Y")
public class SubClass2 extends AbstractBaseClass { ...}
从CommonUrrogateEntity e中选择NEW com.example.subclass 1e.name,e.address,TypeHintEntity t,其中t.type=e.foreignKey


CommonUrrogateEntity将是一个伪类,映射整个公共表。TypeHintEntity就是您在评论中提到的另一个表。

如果可以使用简单的SQL公式确定鉴别器,则可以使用hibernate特有的@DiscriminatorFormula扩展:

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@org.hibernate.annotations.DiscriminatorFormula("(CASE WHEN ... THEN 'SubClass1' ELSE 'SubClass2' END)")
public abstract class AbstractBaseClass {

}

不知道为什么他们没有在JPA标准中包含这个:-.

什么样的SQL查询?基于其他属性或与其他表的联接?其他一些表有两列col1、col2,它们是指向我们的表的外键。如果当前行的id包含在另一个表的col1中,则我们有类型1,否则是另一个类型。您确定域模型正确吗?如果DB人员认为您的两个子类需要在同一个表中,而它们的不同仅仅是因为它们的使用方式不同,例如被称为col1和col2,那么它们可能不是不同的子类,您需要重构它们的差异。也许这是另一个偏好组合而非继承的例子。谢谢,但这是关于维护一个非常复杂和设计糟糕的应用程序的问题,不是我写的。。。。这个设计在很多方面都不好,但它是有效的。我尝试将更改保持在最低限度。我尝试了@DiscriminatorFormulaCASE,当ID从其他_表中选择fk1时,然后“Subclass 1”或“Subclass 2”结束,但我得到了java.sql.SqlSyntaxerException:ORA-00904,因为sql格式不正确。您确定即使案例中的SQL引用另一个表时,这种方法也会起作用吗?从未在oracle中尝试过。你能得到实际生成的SQL吗?是的,问题是Hibernate修改了我的嵌套SQL select,而不是从其他_表中选择fk1,它尝试从其他_表中选择alias.fk1,其中alias指的是原始表,当然没有此列。但如果我提供显式别名,它似乎可以工作!仍然在检查是否一切都正确…我应该把这个JPQL构造函数放在哪里?您的意思是entityManager.createQuery参数?没关系,另一个特定于Hibernate的解决方案只适用于本地更改。不管怎样,你也需要+1。