Jpa Hibernate映射键在多列关系中

时间:2017-03-08 11:59:53

标签: java hibernate jpa

我想映射一个Java Map,其中所有键值都存储在同一个表中。 与https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Example_of_a_map_key_column_relationship_database类似的东西 但是密钥是一个对象,而不是一个简单的类型。

说我有一个实体“用户”

@Entity
public class User{
    @Id
    private String userId;

    @OneToMany
    @MapKeyClass(CalenderWeek.class)
    private Map<CalenderWeek, WorkedTime> workedTimeMap;

关键的CalendarWeek就是这样的

@Embeddable
public class CalenderWeek {
    int year;
    Month month; // Month is the enum java.time.Month

WorkedTime会像

@Embeddable
public class WorkedTime {
    private long workedHours;

相应的工作时间表应该是这样的

worked_time

user_id | year | month | worked_hours
---------|------|-------| ---
 1       | 2017 | 11    | 42

是否有可能实现这一目标 或者我必须按照此处的描述进行操作 https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Example_of_a_map_key_class_embedded_relationship_annotation

即有三张桌子。

3 个答案:

答案 0 :(得分:2)

一般情况下,如果您想要地图,只需使用@ElementCollection注释,如果要覆盖Embeddables中的某些列或关联,则使用{{1} } / @AttributeOverride

@AssociationOverride

根据您是否要覆盖键或值属性,分别为持久性提供程序添加这些前缀,以便能够重新区分差异。

答案 1 :(得分:0)

我假设您希望每月存储用户的工作时间+年。 查看结果表我建议不要使用Embeddable。你可以尝试这种方法:

@Entity
public class User{

    @Id
    private String id;    

    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    private List<WorkedTime> workedTime;

加上后面的参考:

@Entity
public class WorkedTime {

    @Id
    private long id;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    private int year;

    private Month month;

    private long workedHours;

这将导致只有两个表。

答案 2 :(得分:0)

Maciej Kowalski的答案非常有用和正确。谢谢。

我只想在这里完成答案并稍微扩展一下,因为我最后使用了xml配置。 Annotated版本就像那样结束了

@Entity
public class UserWorklogAggregate {
@Id
private String userId;

@ElementCollection
@CollectionTable(
        name = "worked_time",
        joinColumns = @JoinColumn(name = "user_id")
)
@AttributeOverrides({
        @AttributeOverride(name = "key.year", column = @Column(name = "year")),
        @AttributeOverride(name = "key.week", column = @Column(name = "week")),
        @AttributeOverride(name = "value.workedDuration", column = @Column(name = "worked_duration"))
})
private final Map<CalenderWeek, WorkedTime> workedTimeMap = new HashMap<>();

和xml版本

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field" default-cascade="all">

<class name="org.whatever.UserWorklogAggregate" table="user_worklog_aggregate">
    <id name="userId" length="10" column="user_id" />
    <map name="workedTimeMap" table="worked_time" >
        <key column="user_id" />
        <composite-map-key class="org.whatever.CalenderWeek">
            <key-property name="year" column="year"/>
            <key-property name="week" column="week"/>
        </composite-map-key>
        <composite-element class="org.whatever.WorkedTime" >
            <property name="workedDuration" column="worked_duration"/>
        </composite-element>
    </map>
</class>