如何将继承策略与 JPA 注解和 Hibernate 混合使用?

发布于 2024-09-27 06:42:05 字数 1940 浏览 3 评论 0原文

根据 Hibernate 参考文档,在使用 Hibernate 的 XML 元数据时应该可以混合不同的继承映射策略:
http://docs .jboss.org/hibernate/stable/core/reference/en/html/inheritance.html#inheritance-mixing-tableperclass-tablepersubclass

但是,Hibernate Annotations Reference Guide 的相应部分不包括:
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html#d0e1168

另一方面,JavaDocs 建议混合继承策略应该是可能的。例如在 javax.persistence.DiscriminatorColumn 中它说:

策略和鉴别器列仅在应用不同继承策略的实体类层次结构或子层次结构的根中指定。


以下是我试图实现的映射的示例。我想在层次结构根部附近使用每个子类一个表映射,但在叶子附近更改为每个类层次结构一个表映射。下面是一些示例代码:

@Entity
@Inheritance( strategy = InheritanceType.JOINED )
public abstract class A implements Serializable
{
    @Id
    private String id;

    // other mapped properties...
}

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
public class BB extends A
{
    // other mapped properties and associations...
}

@Entity
public class BB1 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
public class BB2 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
public class CC extends A
{
    // other mapped properties and associations...
}

@Entity
public class CC1 extends CC
{
    // other stuff, not necessarily mapped...
}

...

我期望从该映射中得到正好 3 个表:ABBCCBBCC 都应该有一个名为 DTYPE 的默认鉴别器列。它们还应该提供其各自子类的所有映射属性和关联所需的所有列。

相反,类层次结构似乎自始至终都使用每个子类一个表继承策略。即我为上面提到的每个实体都有一个自己的表。我想避免这种情况,因为类层次结构的叶子非常轻量,并且为每个叶子都有一个单独的表似乎有点过分了!


我是不是忽略了什么?任何建议都将受到高度赞赏!我很乐意提供更多信息...

According to the Hibernate Reference Documentation it should be possible to mix different inheritance mapping strategies when using Hibernate's XML-Metadata:
http://docs.jboss.org/hibernate/stable/core/reference/en/html/inheritance.html#inheritance-mixing-tableperclass-tablepersubclass

However, the corresponding section of the Hibernate Annotations Reference Guide does not cover that:
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html#d0e1168

On the other hand, the JavaDocs suggest that mixing inheritance strategies should be possible. For instance in javax.persistence.DiscriminatorColumn it says:

The strategy and the discriminator column are only specified in the root of an entity class hierarchy or subhierarchy in which a different inheritance strategy is applied.


The following is an example for the mapping I'm trying to achieve. I'd like to use table-per-subclass mapping near the root of the hierarchy, but change to table-per-class-hierarchy mapping near the leaves. Here's some example code:

@Entity
@Inheritance( strategy = InheritanceType.JOINED )
public abstract class A implements Serializable
{
    @Id
    private String id;

    // other mapped properties...
}

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
public class BB extends A
{
    // other mapped properties and associations...
}

@Entity
public class BB1 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
public class BB2 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
public class CC extends A
{
    // other mapped properties and associations...
}

@Entity
public class CC1 extends CC
{
    // other stuff, not necessarily mapped...
}

...

What I expect from this mapping is having exactly 3 tables: A, BB, and CC. Both BB and CC should have a default discriminator column called DTYPE. They should also provide all columns necessary for all mapped properties and associations of their respective subclasses.

Instead , the class hierarchy seems to use the table-per-subclass inheritance strategy throughout. I.e. I get an own table for each of the entities mentioned above. I'd like to avoid this, since the leaves of the class-hierarchy are extremely light-weight and it just seems overkill to have a separate table for each of them!


Did I overlook something? Any advice is highly appreciated! I'll be glad to provide additional info...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

べ繥欢鉨o。 2024-10-04 06:42:05

根据 Hibernate 参考文档,在使用 Hibernate 的 XML 元数据时应该可以混合不同的继承映射策略(...)

实际上,它并不真正支持,它们使用辅助表“作弊”从文档示例中的单表策略切换。引用Java Persistence with Hibernate

您可以映射整个继承
通过嵌套进行层次结构
, ,
映射
元素。你不能混合它们——因为
例如,要从
每类一个表的层次结构
判别器归一化
每个子类一个表的策略。 一次
你已经做出了一个决定
继承策略,你必须
坚持下去

然而,这并不完全正确。
通过一些 Hibernate 技巧,您可以
切换映射策略
特定的子类。例如,
可以将类层次结构映射到单个
表,但对于特定的子类,
切换到一个单独的表
外键映射策略
,就像
每个子类都有一个表。这是
可以使用 映射
元素:

;
  <类名=“账单详细信息”
      表 =“BILLING_DETAILS”>

    ...

    <鉴别器
        列=“BILLING_DETAILS_TYPE”
        类型=“字符串”/>
    ...
    <子类
        名称=“信用卡”
        判别器值=“CC”>
      <连接表=“CREDIT_CARD”>
        <关键列=“CREDIT_CARD_ID”/>

        <属性名称=“编号”列=“CC_NUMBER”/>
        <属性名称=“expMonth”列=“CC_EXP_MONTH”/>
        <属性名称=“expYear”列=“CC_EXP_YEAR”/>
        ...
      
    

    <子类
        名称=“银行账户”
        判别器值=“BA”>
      <属性名称=帐户"column="BA_ACCOUNT"/>
      ...
    
  ...
  

你也可以通过注释实现同样的效果:

Java Persistence 还支持这种带有注释的混合继承映射策略。像之前一样,将超类 BillingDetails 映射到 InheritanceType.SINGLE_TABLE。现在将您想要从单个表中分离出来的子类映射到辅助表。

<前><代码>@Entity
@DiscriminatorValue(“CC”)
@SecondaryTable(
名称=“信用卡”,
pkJoinColumns = @PrimaryKeyJoinColumn(name = "CREDIT_CARD_ID")

公共类信用卡扩展了 BillingDetails {
@Column(表=“信用卡”,
名称 =“CC_NUMBER”,
可空=假)
私有字符串号;
...
}

我没有对此进行测试,但您也许可以尝试:

  • 使用 SINGLE_TABLE 策略映射 A,
  • 使用 @SecondaryTable 注释映射 BB、CC 等。

我没有测试过这个,我不知道它是否适用于 BB1、BB2。

参考

  • Java 持久化与 Hibernate
    • 5.1.5 混合继承策略 (p207-p210)

According to the Hibernate Reference Documentation it should be possible to mix different inheritance mapping strategies when using Hibernate's XML-Metadata (...)

Actually, it's not really supported, they are "cheating" using a secondary table to switch from the single table strategy in the example of the documentation. Quoting Java Persistence with Hibernate:

You can map whole inheritance
hierarchies by nesting
<union-subclass>, <sub- class>,
and <joined-subclass> mapping
elements. You can’t mix them — for
example, to switch from a
table-per-class hierarchy with a
discriminator to a normalized
table-per-subclass strategy. Once
you’ve made a decision for an
inheritance strategy, you have to
stick to it
.

This isn’t completely true, however.
With some Hibernate tricks, you can
switch the mapping strategy for a
particular subclass. For example, you
can map a class hierarchy to a single
table, but for a particular subclass,
switch to a separate table with a
foreign key mapping strategy
, just as
with table per subclass. This is
possible with the <join> mapping
element:

<hibernate-mapping>
  <class name="BillingDetails"
      table="BILLING_DETAILS">

    <id>...</id>

    <discriminator
        column="BILLING_DETAILS_TYPE"
        type="string"/>
    ...
    <subclass
        name="CreditCard"
        discriminator-value="CC">
      <join table="CREDIT_CARD">
        <key column="CREDIT_CARD_ID"/>

        <property name="number" column="CC_NUMBER"/>
        <property name="expMonth" column="CC_EXP_MONTH"/>
        <property name="expYear" column="CC_EXP_YEAR"/>
        ...
      </join>
    </subclass>

    <subclass
        name="BankAccount"
        discriminator-value="BA">
      <property name=account" column="BA_ACCOUNT"/>
      ...
    </subclass>
  ...
  </class>
</hibernate-mapping>

And you could achieve the same with annotations:

Java Persistence also supports this mixed inheritance mapping strategy with annotations. Map the superclass BillingDetails with InheritanceType.SINGLE_TABLE, as you did before. Now map the subclass you want to break out of the single table to a secondary table.

@Entity
@DiscriminatorValue("CC")
@SecondaryTable(
    name = "CREDIT_CARD",
    pkJoinColumns = @PrimaryKeyJoinColumn(name = "CREDIT_CARD_ID")
)
public class CreditCard extends BillingDetails {
    @Column(table = "CREDIT_CARD",
        name = "CC_NUMBER",
        nullable = false)
    private String number;
    ...
}

I didn't test this but you could maybe try to:

  • map A using a SINGLE_TABLE strategy
  • map BB, CC, etc using the @SecondaryTable annotation.

I've not tested this, I don't know if it will work well for BB1, BB2.

Reference

  • Java Persistence with Hibernate
    • 5.1.5 Mixing inheritance strategies (p207-p210)
是伱的 2024-10-04 06:42:05

为了清楚起见,这里是将帕斯卡的解决方案应用于我的问题中的示例代码:

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
@DiscriminatorColumn( name = "entityType", 
        discriminatorType = DiscriminatorType.STRING )
public abstract class A implements Serializable
{
    @Id
    private String id;

    // other mapped properties...
}

@Entity
@SecondaryTable( name = "BB" )
public class BB extends A
{
    @Basic( optional = false)
    @Column( table = "BB" )
    private String property1;

    // other mapped properties and associations...
}

@Entity
public class BB1 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
public class BB2 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
@SecondaryTable( name = "CC" )
public class CC extends A
{
    @ManyToOne( optional = false)
    @JoinColumn( table = "CC" )
    private SomeEntity association1;

    // other mapped properties and associations...
}

@Entity
public class CC1 extends CC
{
    // other stuff, not necessarily mapped...
}

...

我已经成功地将这种方法应用于我的问题,并且我将暂时坚持使用它。然而,我仍然看到以下缺点:

  • 鉴别器列位于层次结构的主表中,即根实体A的表中。就我而言,在辅助表 BBCC 中包含鉴别器列就足够了。

  • 每当向 BBCC 的子类添加属性和关联时,他/她都必须指定它们应映射到相应的辅助表。如果有一种方法可以将其设置为默认值,那就太好了。

Just for the sake of clarity, here is Pascal's solution applied to the example code from my question:

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
@DiscriminatorColumn( name = "entityType", 
        discriminatorType = DiscriminatorType.STRING )
public abstract class A implements Serializable
{
    @Id
    private String id;

    // other mapped properties...
}

@Entity
@SecondaryTable( name = "BB" )
public class BB extends A
{
    @Basic( optional = false)
    @Column( table = "BB" )
    private String property1;

    // other mapped properties and associations...
}

@Entity
public class BB1 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
public class BB2 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
@SecondaryTable( name = "CC" )
public class CC extends A
{
    @ManyToOne( optional = false)
    @JoinColumn( table = "CC" )
    private SomeEntity association1;

    // other mapped properties and associations...
}

@Entity
public class CC1 extends CC
{
    // other stuff, not necessarily mapped...
}

...

I've successfully applied this approach to my problem, and I'll stick to it for the time being. However I still see the following disadvantages:

  • The discriminator column is located in the main table for the hierarchy, the table for root-enity A. In my case, it would be sufficient to have the discriminator column in the secondary tables BB and CC.

  • Anytime one adds properties and associations to subclasses of BB or CC, he/she has to specify that they should be mapped to the respective secondary table. Would be nice, if there was a way to make that the default.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文