有没有办法使用SecondaryTable跳转多个表?

时间:2015-12-25 21:51:34

标签: java hibernate

假设我有一个名为UserProfile的主用户表,其上有一个显示名称。

我有各种各样的模块,您可以使用UserProfileModuleId来表示您的ModuleMembership。然后,您可以为每个不同的模块创建一个配置文件,以存储与该模块相关的数据,例如,如果您已注册PokerModule,则会获得PokerProfile

我想将UserProfile的显示名称放在PokerProfile上,但我想以规范化的方式进行操作。我可以通过Hibernate或通过SQL来实现,无论哪种方式都可以。确切的关系是PokerProfile.membership.userProfile.displayName - 如何才能将@Column类放到PokerProfile上?

3 个答案:

答案 0 :(得分:9)

您可以使用derived property获取displayName课程中的PokerProfile,如下所示:

@Formula(
    "(SELECT up.displayName"
        + " FROM ModuleMembership mm"
        + " JOIN UserProfile up"
        + " ON (mm.userProfileId = up.userProfileId)"
        + " WHERE mm.moduleMembershipId = membershipId)")
String displayName;

请注意,派生属性仅使用SQL,而不使用HQL。 membershipId被定义为@JoinColumn属性的membership名称。其他列名称也是类似定义的。

然而,虽然它不是你要求的,但我通常在Java中用这样的东西实现我自己的快捷方式属性,如下所示:

@Transient
public String getDisplayName() {
    if (membership == null) {
        return null;
    }
    UserProfile userProfile = membership.getUserProfile();
    return userProfile == null ? null : userProfile.getDisplayName();
}

对我来说,快捷方式属性比相应的SQL更容易读写。

使用Hibernate 5.0.6.Final对H2数据库版本1.4.190进行了代码示例测试。

答案 1 :(得分:2)

如果我们从面向对象/关系方式考虑给定域,我们可以得出以下关系:

PokerProfile 继承 UserProfile

您可以在" One Table Per Subclass Inheritance"的帮助下与JPA和DBMS建立相同的关系。和外键关系。

因此,您可以定义如下内容:

UserProfile.java

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;


@Entity
@Table(name = "TBL_USER_PROFILE")
@Inheritance(strategy=InheritanceType.JOINED)
public class UserProfile {

    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @Column(name = "DISPLAY_NAME")
    private String displayName;

    public Person() {

    }

    public Person(String displayName) {
        this.displayName = displayName;
    }

    // Getter and Setter methods
}

PokerProfile.java

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

@Entity
@Table(name="TBL_POKER_PROFILE")
@PrimaryKeyJoinColumn(name="ID")
public class PokerProfile extends UserProfile {

    // Properties & Getters & Setters here

}

该模型的优点在于它清楚地表达了所需的功能,当然与父配置文件明显同步。没有解决方法或需要调整。在引擎盖下,它使用PokerProfile& amp;的外键关系。 UserProfile等没有数据冗余。

答案 2 :(得分:1)

Hibernate Formula是优雅的解决方案,但如果它们很复杂(Hibernate解析本机SQL的能力有限),它们可能很难正确。此外,即使您使它们正常工作,性能也可能会受到影响,因为公式可能涉及总是嵌入到最终SQL中的子查询。

我经常使用的方法是创建一个数据库视图,为我做必要的连接,然后将我的实体映射到视图。数据库能够比嵌套子查询更好地优化视图,并且Java代码更清晰,因为其中没有本机SQL。

因此,您可以创建一个数据库视图Membership_Profile和一个映射到它的可重用实体,比如MembershipProfile

@Entity
@Table(name = Membership_Profile)
class MembershipProfile {
   Long moduleMembershipId;
   String displayName;
   // Other properties if needed
}

然后,您可以将此实体与特定配置文件相关联,例如:

@Entity
class PokerProfile {
   @OneToOne(fetch=FetchType.LAZY)
   @JoinColumn(name = "membershipId")
   MembershipProfile membershipProfile;
   ...
}

这种方法的好处是您可以在需要时懒惰地加载displayName(以及任何其他MembershipProfile属性)(从而避免执行视图或子查询的成本)。

创建数据库视图的另一种方法是Hibernate Subselect,这是一种Hibernate(只读)视图,但我希望真正的数据库视图能够更好地运行。

相关问题