如何在 Hibernate 的 XML 文件中声明一对多映射?

How do I declare a one-to-many Map in Hibernate's XML file?

我正在尝试创建一对多映射关系,但在 Hibernate (4.x) 映射文件中声明它时遇到问题。我只是……想不通。

实体类是这样的,我想在其中使用IPLogEntry#ip作为映射键(它是不可变的):

class User {

    private long id;
    private Map<String,IPLogEntry> ipHistory = new HashMap<String,IPLogEntry>();
    ... other fields;

    public void addIPEntry (String ip) {
        IPLogEntry e = ipHistory.get(ip);
        if (e == null) {
            e = new IPLogEntry(this, ip);
            ipHistory.put(ip, e);
        }
        e.doOtherStuff(...);
    }

}

class IPLogEntry {

    private long id;
    private User user;
    private String ip;
    ... other fields;

    IPLogEntry (User user, String ip) {
        this.user = user;
        this.ip = ip;
        ... init other fields;
    }

}

还有像这样的表格:

╔═══════════════════╗   ╔══════════════════════════════════════════════════╗
║ users             ║   ║ ip_log                                           ║
╟─────────────┬─────╢   ╟─────────────┬───────────────┬──────────────┬─────╢
║ id (bigint) │ ... ║   ║ id (bigint) │ user (bigint) │ ip (varchar) │ ... ║
╚═════════════╧═════╝   ╚═════════════╧═══════════════╧══════════════╧═════╝

请注意,ip_log.ip 是映射键 IPLogEntry#ip 字段值。

在多次挥手之后,我的映射尝试失败了(顺便说一下,我现在不需要级联 delete 支持...别问) :

<class name="d13.dao.User" table="users">
    <id name="id"><generator class="native"/></id>
    <map name="ipHistory" cascade="save-update,merge">
        <key column="user"/>
        <map-key column="ip" type="string"/>
        <element type="d13.dao.IPLogEntry"/>
    </map>
    ...
</class>

<class name="d13.dao.IPLogEntry" table="ip_log">
    <id name="id"><generator class="native"/></id>
    <many-to-one name="user" class="d13.dao.User" not-null="true"/>
    <property name="ip" not-null="true"/>
    ...
</class>

这让我在初始化时得到了这个:

Error: creating static hibernate session factoryCould not determine type for: 
    d13.dao.IPLogEntry, 
    at table: users_ipHistory,
    for columns: [org.hibernate.mapping.Column(elt)]

我认为 IPLogEntry 方面是正确的,我遇到问题的是 User 方面和 map 的用法。

我一直在盯着:

我不知道该怎么办。所以我知道这是一个基本问题,但是,我应该使用什么映射描述符来完成这项工作?

嗯,基于注释的映射非常简单

@OneToMany(mappedBy = "user", cascade = { PERSIST, MERGE })
@MapKey(name = "ip")
private Map<String, IPLogEntry> ipHistory = new HashMap<>();

我没有XML映射经验,不过应该是:

<class name="d13.dao.User" table="users">
    <id name="id">
        <generator class="native"/>
    </id>
    <map name="ipHistory" cascade="save-update,merge" inverse="true">
        <key column="user_id"/>
        <map-key column="ip" type="string"/>
        <one-to-many class="d13.dao.IPLogEntry"/>
    </map>
    ...
</class>

<class name="d13.dao.IPLogEntry" table="ip_log">
    <id name="id">
        <generator class="native"/>
    </id>
    <many-to-one name="user" class="d13.dao.User" column="user_id" not-null="true"/>
    <property name="ip" not-null="true"/>
    ...
</class>

Example 7.29. Bidirectional association with indexed collection