【问题标题】:How do you map a "Map" in hibernate using annotations?如何使用注释在休眠中映射“地图”?
【发布时间】:2011-01-20 15:24:20
【问题描述】:

如何使用注释将实体中的字段映射到给定对象,该字段是字符串的“映射”(哈希表)?该对象被注释并且它的实例已经存储在休眠数据库中。

我找到了用简单的键和值定义映射的语法:

<class name="Foo" table="foo">
    ...
    <map role="ages">
         <key column="id"/>
         <index column="name" type="string"/>
         <element column="age" type="string"/>
     </map>
 </class>

奇怪的是,一个实体作为键,一个简单类型作为值,如下所示:

<class name="Foo" table="foo">
    ...
  <map role="ages">
    <key column="id"/>
    <index-many-to-many column="person_id" 
         class="Person"/>
    <element column="age" type="string"/>
  </map>
</class>
<class name="Person" table="person">
    ...
    <property name="name" column="name" 
         type="string"/>
</class>

但是我看不到如何为元素映射的简单键执行此操作,也看不到如何使用注释来执行此操作。

【问题讨论】:

标签: java hibernate orm mapping


【解决方案1】:

您可以简单地使用 JPA 注释 @MapKey(请注意,JPA 注释与 Hibernate 不同,Hibernate @MapKey 映射一个包含映射键的数据库列,而 JPA 的annotation 映射要用作映射键的属性。

@javax.persistence.OneToMany(cascade = CascadeType.ALL)
@javax.persistence.MapKey(name = "name")
private Map<String, Person> nameToPerson = new HashMap<String, Person>();

【讨论】:

  • 谢谢,我会试试这个。这反映了什么样的数据库模式?我正在使用 DB 单元并希望能够使用 XML 填充数据集。这是否使用连接表?如果可以,你能指定表的名称和连接表的列吗?
  • @Omar 它创建一个连接表(默认为 FOO_PERSON)。您可以使用@javax.persistence.JoinTable 控制名称。不确定列。
【解决方案2】:
@CollectionOfElements(fetch = FetchType.LAZY)
@JoinTable(name = "JOINTABLE_NAME",
    joinColumns = @JoinColumn(name = "id"))
@MapKey(columns = @Column(name = "name"))
@Column(name = "age")
private Map<String, String> ages = new HashMap<String, String>();

【讨论】:

  • 这就是我正在寻找的东西,但是如果键是示例中的字符串并且值是另一个对象,我该怎么做?
  • 这看起来类似于映射枚举的注释。
  • @Omar:应该像用您选择的实体类型替换“String”一样简单。您可能需要删除 @Column(name = "age") 并将类似 inverseJoinColumns=@JoinColumn(name="fk_ik") 的内容添加到 @JoinTable-annotation。不过不确定。
  • 我尝试了类似的方法来持久化一个 ArrayList(反向连接列的东西),但是在我的 DBUnit 测试中遇到了一些问题,他们无法删除表来重新填充它们,因为它们之间存在循环依赖关系两张桌子。
  • 您是否尝试将单个数组列表作为映射的值保存?
【解决方案3】:

我知道这个问题已经很老了,但也许这可以帮助某人。

其他可能性是这样的:

@Entity
@Table(name = "PREFERENCE", uniqueConstraints = { @UniqueConstraint(columnNames = { "ID_DOMAIN", "ID_USER", "KEY" })})
public class Preferences {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", unique = true, nullable = false)
    private Long id;

    @Column(name = "ID_DOMAIN", unique = false, nullable = false")
    private Long domainId;

    @Column (name = "PREFERENCE_KEY")
    @Enumerated(EnumType.STRING)
    private PreferenceKey key;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_USER", referencedColumnName = "ID")
    private User user;
}

and 

@Entity
@Table(name = "USER", uniqueConstraints = { @UniqueConstraint(columnNames = { "ID_DOMAIN", "LOGIN" })})
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", unique = true, nullable = false)
    private Long id;

    @Column(name = "ID_DOMAIN", unique = false, nullable = false")
    private Long domainId;

    // more fields

    @ElementCollection(fetch = FetchType.LAZY)
    @JoinColumns({@JoinColumn(name = "ID_USER", referencedColumnName = "ID"), @JoinColumn(name = "ID_DOMAIN", referencedColumnName = "ID_DOMAIN")})
    @OneToMany(targetEntity = Preferences.class, fetch = FetchType.LAZY)
    @MapKey(name = "key")
    private Map<PreferenceKey, Preferences> preferencesMap;
}

这只会产生两个表 User 和 Preferences,注意 PreferenceKey 对于用户进入域是唯一的

【讨论】:

    【解决方案4】:

    您可能应该使用 UserType 或 UserCollectionType。或者,您可以使用自定义元组。

    有关概念,请参阅 hibernate core documentation,有关等效注释方法,请参阅 hibernate annotations documentation

    如果这不是您的要求,请告诉我。

    【讨论】:

    • 我讨厌听起来像个白痴,但我一整天都在看同样的两页,我似乎不明白。我一直在看这种风格: 这似乎是我需要的东西我只是不明白如何将它作为注释。如果元素不是字符串,我也不知道该怎么做。我是不是用错了棍子的一端。
    • 是的,我认为你真的想要一个 UserType,因为这里讨论的所有其他事情(我相信)都会创建另一个表来存储地图。看看 UserType 界面,你会看到那里只是实现的几种方法。基本上你告诉hibernate,给定一个ResultSet,如何把它放入java类型,反之亦然。
    猜你喜欢
    • 2019-06-10
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 2012-02-27
    • 2012-09-05
    • 1970-01-01
    相关资源
    最近更新 更多