我们在应用程序中为每个表使用单表继承。这允许同一应用程序堆栈的不同实例与相同的DAO一起工作,而它们的实体可能略有不同,可能包含该实例特有的信息。抽象类定义基本表结构,如果该实例需要,扩展定义其他列:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "client")
public abstract class Client extends AbstractPersistable<Long> {
// ...
}
申请A:
@Entity
public class ClientSimple extends Client {
private String name;
// getter, setter
}
申请B:
@Entity
public class ClientAdvanced extends Client {
private String description;
// getter, setter
}
现在,DAO可以与应用程序A和B的Client
对象一起使用,但是应用程序B可以为其客户端对象定义其他信息,这些信息可以由应用程序B独有的管理器方法读取:
申请A:
Client client = new ClientSimple();
clientDao.save(client);
申请B:
Client client = new ClientAdvanced();
clientDao.save(client);
不幸的是,这意味着每个表中都有一个DTYPE列(或者我可能选择的任何其他名称)。有没有办法摆脱这个?我们不需要它,它正在耗尽数据库空间......
谢谢!
修改
重要提示:@MappedSuperclass
不起作用。我们使用 QueryDSL 作为我们的HQL抽象层。这需要为类型保存查询自动生成查询类型类。但是,只有在使用@Entity
注释抽象类时才会正确生成这些内容。
这是必要的,因为我们想要查询抽象类Client
,同时实际查询应用程序A中的ClientSimple
和应用程序B中的ClientAdvanced
:
所以在任何应用程序中都可以使用:
query.where(QClient.client.name.equals("something");
并且在应用程序B中这将起作用:
query.where(QClientSimple.client.description.equals("something else");
EDIT2 - 归结
似乎可以归结为:我可以在部署时配置hibernate,以将一个被编入实体的鉴别器类型设置为固定值。因此,在我的示例中,Client
在一个应用程序中始终为ClientSimple
,在另一个应用程序中为ClientAdvanced
,以便我不必将该信息存储在数据库中?
就像我说的:每个应用程序都将是基本应用程序堆栈的一个实例。每个应用程序可能为其本地数据库定义其他列,但所有对象与该实例的类型相同,因此我们保证鉴别器始终相同,使其在数据库中成为冗余,并且是hibernate配置的用例。
答案 0 :(得分:7)
我知道,这是一个非常古老的问题,但我最近遇到了这个问题,这可能对某人有用。
这可以使用Hibernate的@DiscriminatorFormula注释来完成。以下描述基于书籍Java Persistence with Hibernate,第5.1.3节;相关部分从第202页最后一段的页面开始。
使用@DiscriminatorFormula,您可以提供SQL
语句,该语句在从数据库中提取相关行时确定discriminator
的值。在您的情况下,它必须是一个简单的字符串,评估一些任意选择的值。为此,您需要确定将用于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 {
// ...
}
由' 1 '表示的行是SQL代码段的一部分,它将始终返回'GenericClient'作为其值。 subclasses
的{{1}}应始终使用Client
进行注释。这意味着当Hibernate从DB中获取行时,要构造的对象的类型将始终是@DiscriminatorValue("GenericClient")
的特定子类。
如果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> {
// ...
}
默认为discriminator-value
,它本身默认为完全限定的类名。
注意: entity-name
内的SQL
语句可以是目标数据库服务器的任何有效@DiscriminatorFormula()
语句。
答案 1 :(得分:1)
如果您永远不需要在同一个应用中同时使用ClientSimple
和ClientAdvanced
,则可以将Client
声明为@MappedSuperclass
而不是@Entity
。
答案 2 :(得分:1)
在Hibernate中,每个类的单个表层次总是需要一个鉴别器列来区分实体,因为一个层次结构中的所有类都存储在一个表中。 以下是Hibernate Single Table per Class Hierarchy的示例。
但您可能需要考虑不同的层次结构方案,如下所示:
<强> Hibernate Single Table per Subclass 强>
优点
缺点
<强> Hibernate Single Table per Concrete class 强>
优点
缺点
我建议你看看每个子类的单表方案。虽然我不确定你的具体要求。但这可能有所帮助。