我可以删除Hibernate单表继承中的discriminator列吗?

Pet*_*ete 5 java inheritance hibernate single-table-inheritance querydsl

我们对应用程序中的每个表使用单表继承.这允许同一应用程序堆栈的不同实例与相同的DAO一起工作,而它们的实体可能略有不同,可能包含该实例特有的信息.抽象类定义基本表结构,如果该实例需要,扩展定义其他列:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "client")
public abstract class Client extends AbstractPersistable<Long> {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

申请A:

@Entity
public class ClientSimple extends Client {
    private String name;
    // getter, setter
}
Run Code Online (Sandbox Code Playgroud)

申请B:

@Entity
public class ClientAdvanced extends Client {
    private String description;
    // getter, setter
}
Run Code Online (Sandbox Code Playgroud)

现在DAO可以处理Client应用程序A和B的对象,但是应用程序B可以为其客户端对象定义其他信息,这些信息可以由应用程序B特有的管理器方法读取:

申请A:

Client client = new ClientSimple();
clientDao.save(client);
Run Code Online (Sandbox Code Playgroud)

申请B:

Client client = new ClientAdvanced();
clientDao.save(client);
Run Code Online (Sandbox Code Playgroud)

不幸的是,这意味着每个表中都有一个DTYPE列(或者我可能选择的任何其他名称).有没有办法摆脱这个?我们不需要它,它正在耗尽数据库空间......

谢谢!


编辑

重要提示:@MappedSuperclass不起作用.我们使用QueryDSL作为我们的HQL抽象层.这需要为类型保存查询自动生成查询类型类.但是,只有在使用注释抽象类时才会正确生成这些@Entity.

这是必要的,因为我们想Client在实际查询ClientSimple应用程序A和ClientAdvanced应用程序B时查询抽象类:

所以在任何应用程序中都可以使用:

query.where(QClient.client.name.equals("something");
Run Code Online (Sandbox Code Playgroud)

在应用程序B中,这将起作用:

query.where(QClientSimple.client.description.equals("something else");
Run Code Online (Sandbox Code Playgroud)

编辑2 - 归结为

它似乎可以归结为:我可以在部署时配置hibernate,以将已设置实体的鉴别器类型设置为固定值.因此,使用我的示例a Client将始终ClientSimple在一个应用程序中,而在另一个应用程序ClientAdvanced中,以便我不必将该信息存储在数据库中?

就像我说的:每个应用程序都将是基本应用程序堆栈的一个实例.每个应用程序可能为其本地数据库定义其他列,但所有对象与该实例的类型相同,因此我们保证鉴别器始终相同,使其在数据库中成为冗余,并且是hibernate配置的用例.

Bha*_*ikh 7

我知道,这是一个非常古老的问题,但我最近遇到了这个问题,这可能对某人有用.

这可以使用Hibernate的@DiscriminatorFormula注释来完成.以下描述基于Java Persistence with Hibernate一书,第5.1.3节; 相关部分从第202页最后一段的页面开始.

使用@DiscriminatorFormula,您可以提供一个SQL语句,用于确定discriminator从数据库中获取相关行的while 值.在您的情况下,它必须是一个简单的字符串,评估一些任意选择的值.为此,您需要确定将用于您的Client实体的名称.假设您选择'GenericClient'作为.的名称entity.这是应@Entity作为name属性值出现在注释中的名称.因此,完整的示例,在您的情况下将如下所示.

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "client")
@DiscriminatorFormula("'GenericClient'")  // *1*
public abstract class Client extends AbstractPersistable<Long> {
    // ...
}

// Application A
@Entity
@DiscriminatorValue("GenericClient")  // *2*
public class SimpleClient extends Client {
    // ...
}


// Application B
@Entity
@DiscriminatorValue("GenericClient")  // *3*
public class AdvancedClient extends Client {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

由' 1 ' 表示的行是SQL片段的一部分,它将始终返回'GenericClient'作为其值.该subclassesClient应该始终与注解@DiscriminatorValue("GenericClient").这意味着当Hibernate从DB中获取行时,要构造的对象的类型将始终是特定的子类Client.

如果Client驻留子类的包和子类的名称是固定的:

在这种情况下,@DiscriminatorValue("GenericClient")不需要子类,您需要做的就是:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "client")
@DiscriminatorFormula("'com.example.fixed.path.FixedSubClassName'")
public abstract class Client extends AbstractPersistable<Long> {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

子类不需要任何注释.该discriminator-value默认为entity-name,这本身默认为完全合格的类名.

注:SQL内部的语句@DiscriminatorFormula()可以是任何有效的SQL为您的目标数据库服务器的语句.


axt*_*avt 2

如果您从不需要在同一个应用程序中使用两者ClientSimpleClientAdvanced则可以声明Client@MappedSuperclass而不是@Entity