假设我有一个名为UserProfile
的主用户表,其上有一个显示名称。
我有各种各样的模块,您可以使用UserProfile
和ModuleId
来表示您的ModuleMembership
。然后,您可以为每个不同的模块创建一个配置文件,以存储与该模块相关的数据,例如,如果您已注册PokerModule
,则会获得PokerProfile
。
我想将UserProfile
的显示名称放在PokerProfile
上,但我想以规范化的方式进行操作。我可以通过Hibernate或通过SQL来实现,无论哪种方式都可以。确切的关系是PokerProfile.membership.userProfile.displayName
- 如何才能将@Column
类放到PokerProfile
上?
答案 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(只读)视图,但我希望真正的数据库视图能够更好地运行。