2017-03-08 177 views
1

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

说我有一个实体的 “用户”

@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

即,三个用表。

回答

1

一般来说,如果你想有一个地图ü只需使用@ElementCollection注释,如果你想覆盖一些列或协会从Embeddables然后使用@AttributeOverride/@AssociationOverride的:

@ElementCollection 
@AttributeOverrides({ 
@AttributeOverride(name="key.year", 
[email protected](name="YEAR1")), 
@AttributeOverride(name="value.workedHours", 
[email protected](name="WORKED_H")) 
}) 
private Map<CalenderWeek, WorkedTime> workedTimeMap; 

根据无论是要覆盖键还是值属性,都要分别为持久性提供程序添加这些前缀,以便能够重新识别差异。

+0

只是为了让它完成@CollectionTable( 名= “worked_time”, joinColumns = @ JoinColumn(名=“user_id”) ) 也是需要的。 – fan

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; 

这将导致只有两个表。

0

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

我只想在这里完成答案,并稍微扩展它,因为我在最后使用了xml配置。 的注释版本结束这样的

@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>